3

我有一个有趣的问题,对于刚接触 Scala 的人来说很难。
我需要合并 2 个列表:

listA : List[List[Int]]
listB : List[Int]

通过以下方式:

val listA = List(List(1,1), List(2,2))
val listB = List(3,4)
val listC = ???

// listC: List[List[Int]] = List(List(1,1,3),List(1,1,4),List(2,2,3),List(2,2,4)

在 Java 中,我会使用几个嵌套循环:

for(List<Integer> list : listA) {
    for(Integer i: listB) {
        subList = new ArrayList<Integer>(list);
        subList.add(i);
        listC.add(subList);
    }
}

我猜这是 Scala 中的一个单行,但到目前为止它一直在躲避我。

4

2 回答 2

9

您想要执行扁平的笛卡尔积。For-comprehensions 是执行此操作的最简单方法,可能看起来类似于您的 Java 解决方案:

val listC = for (list <- listA; i <- listB) yield list :+ i
于 2013-09-19T10:48:40.487 回答
7

scand1sk答案几乎可以肯定是您应该在这里使用的方法,但作为旁注,还有另一种思考这个问题的方法。您所做的实际上是将附加操作提升到列表的应用函子中。这意味着使用Scalaz您可以编写以下内容:

import scalaz._, Scalaz._

val listC = (listA |@| listB)(_ :+ _)

我们可以将其(_ :+ _)视为一个函数,它接受一个事物列表和一个相同类型的事物,并返回一个新列表:

(_ :+ _): ((List[Thing], Thing) => List[Thing])

Scalaz 为列表提供了一个应用函子实例,因此我们实际上可以创建一个新函数,为上述每种类型添加一个额外的列表层。奇怪的(x |@| y)(_ :+ _)语法说:创建这样一个函数并将其应用于xand y。结果就是你要找的。

和在理解的情况下一样,如果你不关心顺序,你可以通过使用::和翻转参数的顺序来提高操作的效率。

有关更多信息,请参阅我在此处关于 Haskell 中的笛卡尔积的类似答案、对 Scala中的应用函子的介绍,或这篇关于在 Scala 中使此类事物的语法不那么难看的博客文章。如果您不在乎,当然可以随意忽略以上所有内容。

于 2013-09-19T11:53:46.337 回答