计算List

时间:2017-05-30 18:59:38

标签: java scala permutation scala-collections

请求

由于这个问题专门针对Scala编程语言,因此Java中的解决方案也可以。然而,需要注意的一个小问题是,在Scala解决方案中tail recursion(Scaladocs)绝对优于其他解决方案,而在Java中,非递归解决方案是有利的。这是因为它需要在相当大的数据结构上工作,以便每个项目包含在"最好是懒惰的流或类似的"可以相应地处理,而不会收到StackOverflowError(Javadocs)(多么具有讽刺意味)。

应该置换的数据类型是Scala List(Scaladoc),但是使用Java数组和一个有点错综复杂的循环结构来回应完全没问题。

单个列表的排列问题

在Scala中,以下是检索给定集合类型的所有排列的完全有效的方法。以下方法以惰性方式返回包含所有排列的迭代器:

val permutations = List(1, 2, 3, 4, 5, 6, 7).permutations.take(5)

如前所述,这将产生一个包含该特定List的排列的迭代器。由于它很懒,我们只能从序列中取出五个。根据我的理解,这很好,只要我们不在迭代器上调用toString,因为这会导致迭代器计算所有可用数据并将其作为String返回。

虽然懒惰,但这不会解决我的问题。我所追求的是以下内容:

// List of lists
val lists = List(
        List(1, 2, 3), 
        List(3, 2), 
        List(4, 3, 2, 4))

计算内部List的所有可能排列,同时保持外部List内List的相同排序,外部List中每个List包含的元素数量相同。意思是,内部列表应该以各种可能的方式与其他内部列表一起进行置换,就像它们已被展平一样,同时仍保持相同的顺序并包含与之前相同数量的元素。

因此,一个排列可能会产生:

List(List(1, 3, 2), List(3, 2), List(3, 4, 4, 2))

此外

似乎我不够聪明,无法自己克服这里列出的概念。任何指针,如果不是完整的代码,将非常感谢!如果您有任何问题,请写下评论,我会尽力澄清,或者通过评论或对现有问题进行少量修改。

如果你对这个问题有一个答案,但是用这个问题没有列出的语言,尽可能尝试回答,这主要是我所追求的这种排列的概念!

2 个答案:

答案 0 :(得分:1)

如果外部List的大小已知并且不变,那么可以按如下方式完成。

val ls = List(List(1, 3, 2), List(7, 8), List(9, 4, 4, 5))

val allPerms: Iterator[List[List[Int]]] = for {
  a <- ls(0).permutations
  b <- ls(1).permutations
  c <- ls(2).permutations
} yield List(a,b,c)

在此示例中,生成的Iterator有144个元素,这是我们应该期望的:6 X 2 X 12 = 144

如果外List长度是流动的,则任务有点复杂。

<强>更新

在这种情况下&#34;更复杂&#34;意味着在提出可能的解决方案之前,我必须对其进行一段时间的研究。

def getAllPerms[A]( in: List[List[A]]
                  , acc: List[List[A]] = List()
                  ): Iterator[List[List[A]]] = in match {
  case end :: Nil => end.permutations.map(acc :+ _)
  case hd :: tl => hd.permutations.flatMap(x => getAllPerms(tl, acc :+ x))
  case Nil => Iterator()  // just to be complete
}

这是递归的,但不是尾递归的。它确实通过了我有限的一组测试。试一试。

答案 1 :(得分:1)

尾递归,懒惰评估解决方案:

@tailrec
def tailRecCombineWith(permutatedLists: Iterator[List[List[Int]]], remainingLists: List[List[Int]]): Iterator[List[List[Int]]] = remainingLists match {
  case Nil => permutatedLists
  case head :: tail => tailRecCombineWith(for {
    a: List[List[Int]] <- permutatedLists
    b: List[Int] <- head.permutations
  } yield a :+ b, tail)
}

val result: Iterator[List[List[Int]]] = 
  tailRecCombineWith(lists.head.permutations.map(List(_)), lists.tail)