我在Scala中有一个列表列表如下。
val inputList:List[List[Int]] = List(List(1, 2), List(3, 4, 5), List(1, 9))
我想要一份所有子列表的交叉产品列表。
val desiredOutput: List[List[Int]] = List(
List(1, 3, 1), List(1, 3, 9),
List(1, 4, 1), List(1, 4, 9),
List(1, 5, 1), List(1, 5, 9),
List(2, 3, 1), List(2, 3, 9),
List(2, 4, 1), List(2, 4, 9),
List(2, 5, 1), List(2, 5, 9))
inputList中的元素数量以及子列表不固定。 Scala的做法是什么?
答案 0 :(得分:4)
这是一个使用递归的方法。但是它不是尾递归的,所以要注意stackoverflow。但是,它可以通过使用辅助函数转换为尾递归函数。
def getProduct(input:List[List[Int]]):List[List[Int]] = input match{
case Nil => Nil // just in case you input an empty list
case head::Nil => head.map(_::Nil)
case head::tail => for(elem<- head; sub <- getProduct(tail)) yield elem::sub
}
测试:
scala> getProduct(inputList)
res32: List[List[Int]] = List(List(1, 3, 1), List(1, 3, 9), List(1, 4, 1), List(1, 4, 9), List(1, 5, 1), List(1, 5, 9), List(2, 3, 1), List(2, 3, 9), List(2, 4, 1), List(2, 4, 9), List(2, 5, 1), List(2, 5, 9))
答案 1 :(得分:4)
如果您使用scalaz
,这可能适用于Applicative Builder
:
import scalaz._
import Scalaz._
def desiredOutput(input: List[List[Int]]) =
input.foldLeft(List(List.empty[Int]))((l, r) => (l |@| r)(_ :+ _))
desiredOutput(List(List(1, 2), List(3, 4, 5), List(1, 9)))
我自己并不熟悉scalaz,我希望它有更强大的魔力来做到这一点。
修改
正如Travis Brown所说,我们只写
def desiredOutput(input: List[List[Int]]) = input.sequence
我发现this question的答案非常有助于理解sequence
的作用。
答案 2 :(得分:2)
如果你不介意一些函数式编程:
def cross[T](inputs: List[List[T]]) : List[List[T]] =
inputs.foldRight(List[List[T]](Nil))((el, rest) => el.flatMap(p => rest.map(p :: _)))
很有趣,找出它是如何工作的。 : - )
答案 3 :(得分:1)
经过多次尝试,我得出了这个解决方案。
val inputList: List[List[Int]] = List(List(1, 2), List(3, 4, 5), List(1, 9))
val zss: List[List[Int]] = List(List())
def fun(xs: List[Int], zss: List[List[Int]]): List[List[Int]] = {
for {
x <- xs
zs <- zss
} yield {
x :: zs
}
}
val crossProd: List[List[Int]] = inputList.foldRight(zss)(fun _)
println(crossProd)