输入:
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))
但它似乎不是最佳的,有没有更好的方法呢?
答案 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。我在机器学习领域用它来生成特征空间中每对变量之间的所有产品,如果两个或多个变量具有相同的值,我仍然希望生成一个与其产品相对应的新变量,即使这些变量是新的生成的“交互变量”将有重复。