在Scala中使用元组

fri*_*rio 6 scala tuples

我想做这样的事情(非常简化):

((1, 2, 3, 4, 5, 6), (6, 5, 4, 3, 2, 1)).zipped map (_ + _)
Run Code Online (Sandbox Code Playgroud)

忽略整数的实际值(尽管重要的是这些是6元组,实际上:)).本质上,我想在一个维持Map[String, (Int, Int, Int, Int, Int, Int)]现有元素更新时间的函数中定期使用它.

事实上,Scala向我吐了出来:

<console>:6: error: could not find implicit value for parameter w1: ((Int, Int, Int, Int, Int, Int)) => scala.collection.TraversableLike[El1,Repr1]
   ((1, 2, 3, 4, 5, 6), (6, 5, 4, 3, 2, 1)).zipped
Run Code Online (Sandbox Code Playgroud)

如果我使用Seqs而不是元组,一切正常,但我想在类型系统中强制执行6(我可能type Record = (Int, Int, Int, Int, Int, Int)很快就会做一个快速重构).

任何人都可以提供一些关于我做错的建议/为什么Scala不会处理上面的代码?我认为如果我使用2或3-arity元组,看看Scala定义Tuple2Tuple3s(我知道在任意n-arity中缩放元组函数很困难),它可能会有效,但我得到了同样的错误.

提前感谢您提供的任何帮助:).

Rex*_*err 8

您只想映射具有相同类型的元组 - 否则映射没有意义 - 但是Tuple在其类型签名中不包含它.但是如果你愿意做一些工作,你可以设置它,以便元组以你要求的方式工作:

基础:

class TupTup6[A,B](a: (A,A,A,A,A,A), b: (B,B,B,B,B,B)) {
  def op[C](f:(A,B)=>C) = ( f(a._1,b._1), f(a._2,b._2), f(a._3,b._3), 
                            f(a._4,b._4), f(a._5,b._5), f(a._6,b._6) )
}
implicit def enable_tuptup6[A,B](ab: ((A,A,A,A,A,A),(B,B,B,B,B,B))) = {
  new TupTup6(ab._1,ab._2)
}
Run Code Online (Sandbox Code Playgroud)

用法:

scala> ((1,2,3,4,5,6) , (6,5,4,3,2,1)) op { _ + _ }
res0: (Int, Int, Int, Int, Int, Int) = (7,7,7,7,7,7)
Run Code Online (Sandbox Code Playgroud)


psp*_*psp 6

我收到了这个小灵感.

class TupleZipper[T <: Product](t1: T) {
  private def listify(p: Product) = p.productIterator.toList
  def zipWith(t2: T) = (listify(t1), listify(t2)).zipped
}
implicit def mkZipper[T <: Product](t1: T) = new TupleZipper(t1)

// ha ha, it's arity magic
scala> ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2))                      
<console>:8: error: type mismatch;
 found   : (Int, Int, Int, Int, Int)
 required: (Int, Int, Int, Int, Int, Int)
       ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2))
                                     ^

scala> ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2, 1))                   
res1: (List[Any], List[Any])#Zipped[List[Any],Any,List[Any],Any] = scala.Tuple2$Zipped@42e934e

scala> res1 map ((x, y) => x.asInstanceOf[Int] + y.asInstanceOf[Int])      
res2: List[Int] = List(7, 7, 7, 7, 7, 7)
Run Code Online (Sandbox Code Playgroud)

是的,一堆Anys出来了另一端.当你试图以这种方式强迫自己使用元组时,你可以做的并不是真正的惊心动魄.

编辑:哦,当然类型系统在这里给你完整的monty.

scala> ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2, "abc"))         
<console>:8: error: type mismatch;
 found   : java.lang.String("abc")
 required: Int
       ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2, "abc"))
                                                     ^
Run Code Online (Sandbox Code Playgroud)


Itt*_*ayD 5

import scala.collection._

type Record = (Int, Int, Int, Int, Int, Int)

implicit def toIterable(r: Record) = new Iterable[Int]{
  def iterator = r.productIterator.asInstanceOf[Iterator[Int]]
}

implicit def cbf[From <: Iterable[Int]] = new generic.CanBuildFrom[From, Int, Record] {
    def apply(from: From) = apply
    def apply = new mutable.Builder[Int, Record] {
      var array = Array.ofDim[Int](6)
      var i = 0

      def +=(elem: Int) = {
        array(i) += elem
        i += 1
        this
      } 

      def clear() = i = 0

      def result() = (array(0), array(1), array(2), array(3), array(4), array(5))

    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

scala> ((1, 2, 3, 4, 5, 6), (6, 5, 4, 3, 2, 1)).zipped.map{_ + _}
res1: (Int, Int, Int, Int, Int, Int) = (7,7,7,7,7,7)
Run Code Online (Sandbox Code Playgroud)