Scala - 崩溃多个Seqs

时间:2016-08-24 17:48:35

标签: scala recursion collections

如何变换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
}

2 个答案:

答案 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)到单个元素序列。所有这些都是我们构建其余解决方案的基本序列。

鉴于此基础,我们考虑如果我们的inputtail)和一些新序列(head)中存在未知数量的其他序列会发生什么 - 这是称为一般情况。我们可以相信,process将为其余所有序列返回正确的解决方案,因此我们可以使用process(tail)执行此操作。现在我们只需要使用head来获取并转换它。

同样,我们希望在所有结果序列中map。如果处理tail返回Seq(Seq(3), Seq(4)),我们的headSeq(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映射,因此应用每个头元素的结果都以相同的顺序结束。 (为读者练习:如果第二个mapflatMap替换会怎样?)

因此,给定tail的正确处理,我们知道我们可以添加任意序列并获得正确的输出。这就是所需要的,以及递归的魔力!