在Scala中使用zipWith(映射多个Seq)

bsd*_*ish 34 functional-programming scala higher-order-functions

假设我有

val foo : Seq[Double] = ...
val bar : Seq[Double] = ...
Run Code Online (Sandbox Code Playgroud)

我希望产生一个seq,其中baz(i)= foo(i)+ bar(i).我能想到的一种方法是

val baz : Seq[Double] = (foo.toList zip bar.toList) map ((f: Double, b : Double) => f+b)
Run Code Online (Sandbox Code Playgroud)

然而,这感觉既丑陋又低效 - 我必须将seqs转换为列表(使用惰性列表进行爆炸),创建此临时元组列表,仅映射它并让它进行GCed.也许溪流解决了懒惰的问题,但无论如何,这感觉就像不必要的丑陋.在lisp中,map函数将映射多个序列.我会写的

(mapcar (lambda (f b) (+ f b)) foo bar)
Run Code Online (Sandbox Code Playgroud)

并且不会在任何地方创建临时列表.在Scala中是否存在map-over-multiple-lists函数,或者zip是否与解构相结合实际上是"正确"的方法?

Mar*_*sky 82

在Scala 2.8中:

val baz = (foo, bar).zipped map (_ + _)
Run Code Online (Sandbox Code Playgroud)

并且它以相同的方式适用于两个以上的操作数.即你可以跟着这个:

(foo, bar, baz).zipped map (_ * _ * _)
Run Code Online (Sandbox Code Playgroud)

  • 正确,`zipped`仅在`Tuple2`和`Tuple3`上定义.对Arity进行抽象是Scala(以及大多数其他静态类型语言)的最终前沿之一.HLists提供了一种可能性...... (15认同)
  • @retronym还有我们在Haskell中使用ZipLists的`<*>`/`<$>`方法,由于curried函数的同质性,你实际上并不需要抽象arity.因此,如果我想使用5参数`f`进行压缩,我可以或多或少地执行`f <$> xs <*> ys <*> zs <*> ps <*> qs`.不幸的是,在Scala中处理curry函数会更加痛苦:(也许有些想法可以延续下去,因为这种方法似乎比`HList`更优雅. (7认同)

Ale*_*nov 16

调用所需的函数zipWith,但它不是标准库的一部分.它将在2.8(更新:显然不是,见评论).

foo zipWith((f: Double, b : Double) => f+b) bar
Run Code Online (Sandbox Code Playgroud)

这张Trac票.

  • 为了清楚(我相信Daniel会同意),Scala没有什么可以在这里道歉的 - 你用Scala得到的更好.请参阅下面的马丁答案和丹尼尔的答案.如果有人能让马丁获得这个问题的批准答案,那将是很好的... (4认同)
  • 对不起,Scala 2.8上没有zipWith. (3认同)

Dan*_*ral 10

嗯,缺乏拉链,是Scala 2.7 Seq的缺陷.Scala 2.8有一个经过深思熟虑的收藏设计,取代了2.7中收藏品的临时方式(请注意,它们并非都是一次性创建,采用统一设计).

现在,当你想避免创建临时集合时,你应该在Scala 2.7上使用"projection",或者在Scala 2.8上使用"view".这将为您提供一种集合类型,其中某些指令(尤其是map,flatMap和filter)是非严格的.在Scala 2.7上,List的投影是一个Stream.在Scala 2.8上,有一个Sequence的SequenceView,但是在Sequence中有一个zipWith,你甚至不需要它.

话虽如此,如上所述,JVM已经过优化,可以处理临时对象分配,并且在服务器模式下运行时,运行时优化可以创造奇迹.所以,不要过早优化.在将要运行的条件下测试代码 - 如果您还没有计划在服务器模式下运行代码,那么重新考虑如果代码预计会长时间运行,并在必要时选择何时/何时/.

编辑

Scala 2.8实际上可以使用的是:

(foo,bar).zipped.map(_+_)
Run Code Online (Sandbox Code Playgroud)