使用 map 函数将两个 seqs 转换为一个。斯卡拉

Use map function to transform two seqs into one. Scala

在 clojure 中,我们有一个映射函数,您可以在其中提供一个函数和两个集合

(map + [1 2 ] [4 5 ]) ;;=> (5 7 )

Scala 中有类似的东西吗?

我尝试理解,但后来我得到了 4 个组合。

如果有理解的方法就更好了,因为我以后要做一些过滤/

可以先用.zip将两个集合合二为一,再映射:

seq1.zip(seq2).map { case (x, y) => x + y }

我认为 for-comprehension 是不可能的。您也可以通过调用 .filter.filterNot 进行过滤。

这里并没有真正添加任何新内容,但也许这会有所帮助:

def mapCollections[A,B,C](as: Seq[A], bs: Seq[B])(f: (A,B) => C): Seq[C] = 
  as zip bs map f.tupled

mapCollections(List(1, 2), List(4, 5))(_ + _) // = List(5, 7)

@JoeK给你具体的答案

我将为您提供两个更笼统的答案。 Clojure 和许多其他动态语言通常会对元数进行抽象(标准库的 mapapply 函数就是很好的例子)。在没有依赖类型的情况下,这在静态类型语言中很难做到。您将看到的一般模式是根据需要多次重复应用函数。在这种情况下,如果你需要做

(map + [1 2 3] [4 5 6] [7 8 9])

你需要做

xs.zip(ys).zip(zs).map{ case (x, (y, z)) => x + y + z }

一般来说,这个额外的样板文件并不可怕。当你想对任意元组或任意情况 类 进行抽象时,对 arity 的抽象变得更加被遗漏。这就是 Shapeless,一个为您提供有限形式的依赖类型的 Scala 库,发挥作用的时候。

虽然我不会因为这样的事情而打破 Shapeless。

第二个一般要点是,您不能以您要求的方式压缩列表以进行理解(一般情况下不是...因为您可以比较 Scala 中的所有内容以获得相等性,您可以使用一个最终的过滤器通过,但对于任何内置平等不能给你你想要的东西的地方都会失败)。这背后的一般原则有点微妙。事实证明,这些收集功能存在权力等级。您从 map 开始。如果您添加 zipList.apply,您将跳到下一个级别。如果将 zip 替换为 flatten,您将获得另一个级别。使用 flatten 可以恢复 zip 的版本,但反之则不行。

默认的 Scala flatMapflatten(注意 for 理解最终是一系列 flatMap 调用)集合确实产生了 zip,即具有相同类型签名的东西,但正如您所注意到的那样,结果是笛卡尔积。

flatten 的一个版本确实产生了标准 zip,但只有当您的所有集合的长度都相同时才有意义。它涉及取方阵的对角线,该方阵是从一组集合中得出的。

这对于有限集合通常没有用,因为 Scala 的类型系统不够强大,无法表达恒定长度约束,如果不确保长度一致,您可能会出现一些奇怪的行为。

另一方面,这是 flattenflatMap 的版本,它实际上对无限流有用(其中 List.apply 的等价物是无限恒定流),而"normal" 版本的 flatten 将无法通过处理第一个流。

旁注:您当然可以稍后在 for comprehension 中始终使用压缩列表(您可以在其中进行一些过滤)。您只是无法在 for comprehension 中实现压缩本身。