如何变换Seq [Seq [Int],使每个内部Seq包含其他两个列表中的元素?
//Example:
val A = Seq(1, 2, 3)
val B = Seq(4, 5)
val C = Seq(6, 7, 8)
val input(A,B,C)
/**
* INPUT: [(1,2,3), (4,5), (6,7,8)]
* OUTPUT:[(1,4,6), (1,4,7), (1,4,8), (1,5,6), ..., (3,5,8)]
*/
def process(input: Seq[Seq[Int]]): Seq[Seq[Int]] = {
//unknown
}
答案 0 :(得分:1)
如果这是一个家庭作业,我建议你不要转入以下内容(你可能会反向设计一个更简单的解决方案,包括我猜的递归)。但是,如果你真的对此感到好奇,那就有一些非常巧妙的技巧。
def convert[T](xs: Seq[Seq[T]]): Seq[Seq[T]] =
xs.foldLeft(Seq(Seq[T]()))((bs,ns) => for (b <- bs; n <- ns) yield b :+ n)
foldLeft
强调了这样一个事实,即您将从输入的左侧开始,按照您的方式一次Seq
。然后,对于你找到的每个Seq
,你会得到各种笛卡尔积。
scala> convert(Seq(Seq(1,2,3), Seq(4,5), Seq(6,7,8)))
res: Seq[Seq[Int]] = List(List(1, 4, 6), List(1, 4, 7), List(1, 4, 8),
List(1, 5, 6), List(1, 5, 7), List(1, 5, 8), List(2, 4, 6), List(2, 4, 7),
List(2, 4, 8), List(2, 5, 6), List(2, 5, 7), List(2, 5, 8), List(3, 4, 6),
List(3, 4, 7), List(3, 4, 8), List(3, 5, 6), List(3, 5, 7), List(3, 5, 8))
答案 1 :(得分:0)
这是操纵列表列表(或您的案例中的序列)的标准递归概念。关键是颠倒你的想法,并考虑你如何建立&#39;每个候选案例。请注意,正如其他解决方案所示,有几种方法可以解决这个问题,所有这些方法或多或少地相互减少。
我在这里展示的解决方案是正确的,除了订购(故意)。但它应该显示必要的概念:
def process(input: Seq[Seq[Int]]): Seq[Seq[Int]] = input match {
case Nil => Seq()
case head :: Nil => head.map((element: Int) => Seq(element))
case (head: Seq[Int]) :: tail => process(tail).flatMap(
(tailSeq: Seq[Int]) => {
head.map((element: Int) => element +: tailSeq)
})
}
// In the worksheet
val processResult = process(input) // Visual inspection shows correctness
processResult.length == (A.length * B.length * C.length) // Just verify we get the correct number of values
在考虑递归时,您应该做的第一件事是考虑基本情况。在这种情况下,如果input
列表为空,会发生什么?我们知道这是一个空Seq
。这很有用,因为我们可以在它之上构建我们的解决方案。现在,我作了一点作弊并提出了第二个基本案例(任何不能解决的案例都是一个基本案例)我们只有一个序列:我们知道这个序列是一系列序列,其中每个子序列只有一个元素。
我们使用map
构建此内容,我们转换或“映射”#输入序列中的每个元素(head
)到单个元素序列。所有这些都是我们构建其余解决方案的基本序列。
鉴于此基础,我们考虑如果我们的input
(tail
)和一些新序列(head
)中存在未知数量的其他序列会发生什么 - 这是称为一般情况。我们可以相信,process
将为其余所有序列返回正确的解决方案,因此我们可以使用process(tail)
执行此操作。现在我们只需要使用head
来获取并转换它。
同样,我们希望在所有结果序列中map
。如果处理tail
返回Seq(Seq(3), Seq(4))
,我们的head
为Seq(1,2)
,我们知道我们需要Seq(Seq(1,3), Seq(1,4), Seq(2,3), Seq(2,4)
作为结果。外部地图(实际上flatMap
)依次获取每个结果序列,并使用map
到 prepend (+:
) head
序列中的每个元素。
如果我们使用map
代替flatMap
,结果将是:Seq(Seq(Seq(1,3), Seq(1,4)), Seq(Seq(2,3), Seq(2,4)))
。 flatMap
所做的只是简单地“扁平化”&#39; head
映射,因此应用每个头元素的结果都以相同的顺序结束。 (为读者练习:如果第二个map
被flatMap
替换会怎样?)
因此,给定tail
的正确处理,我们知道我们可以添加任意序列并获得正确的输出。这就是所需要的,以及递归的魔力!