Scala从列表中生成唯一对

时间:2014-10-29 10:34:00

标签: scala functional-programming

输入:

val list = List(1, 2, 3, 4)

期望的输出:

Iterator((1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4))

此代码有效:

for (cur1 <- 0 until list.size; cur2 <- (cur1 + 1) until list.size)
  yield (list(cur1), list(cur2))

但它似乎不是最佳的,有没有更好的方法呢?

2 个答案:

答案 0 :(得分:23)

There's a .combinations method built-in

scala> List(1,2,3,4).combinations(2).toList
res0: List[List[Int]] = List(List(1, 2), List(1, 3), List(1, 4), List(2, 3), List(2, 4), List(3, 4))

它返回Iterator,但我添加.toList只是为了打印结果。如果您希望以元组形式显示结果,可以执行以下操作:

scala> List(1,2,3,4).combinations(2).map{ case Seq(x, y) => (x, y) }.toList
res1: List[(Int, Int)] = List((1,2), (1,3), (1,4), (2,3), (2,4), (3,4))

您也提到了唯一性,因此您可以将.distinct应用于您的输入列表,唯一性不是您的功能的前提条件,因为.combination不会为您进行重复数据删除。

答案 1 :(得分:0)

.combinations是生成任意大小的唯一任意组的正确方法,另一种不首先检查唯一性的替代解决方案是使用foldLeft:

val list = (1 to 10).toList

val header :: tail = list
tail.foldLeft((header, tail, List.empty[(Int, Int)])) {
  case ((header, tail, res), elem) =>
    (elem, tail.drop(1), res ++ tail.map(x => (header, x)))
}._3

将产生:

res0: List[(Int, Int)] = List((1,2), (1,3), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,10), (2,3), (2,4), (2,5), (2,6), (2,7), (2,8), (2,9), (2,10), (3,4), (3,5), (3,6), (3,7), (3,8), (3,9), (3,10), (4,5), (4,6), (4,7), (4,8), (4,9), (4,10), (5,6), (5,7), (5,8), (5,9), (5,10), (6,7), (6,8), (6,9), (6,10), (7,8), (7,9), (7,10), (8,9), (8,10), (9,10))

如果您希望有重复项,那么您可以将输出列表转换为一个集合并将其恢复到列表中,但是您将失去排序。因此,如果您想要具有唯一性,则不是推荐的方式,但如果您想要生成包含相等元素的所有对,则应该首选。

E.g。我在机器学习领域用它来生成特征空间中每对变量之间的所有产品,如果两个或多个变量具有相同的值,我仍然希望生成一个与其产品相对应的新变量,即使这些变量是新的生成的“交互变量”将有重复。