2012-08-03 55 views
7

我是斯卡拉的全新人员,他对Haskell的函数式编程经验非常有限。编写所有对的列表

我想尝试编写从单个输入列表构建的所有可能的对列表。例如:

val nums = List[Int](1, 2, 3, 4, 5) // Create an input list 
val pairs = composePairs(nums)  // Function I'd like to create 

// pairs == List[Int, Int]((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1) ... etc) 

我试图与整个列表中的每个元素上使用zip,希望它在整个复制一个项目。它没有工作(只匹配第一个可能的对)。我不知道如何重复一个元素(Haskell与cycletake我相信),而且我在遵循Scala文档时遇到了麻烦。

这让我想到可能有更简洁,功能更强的方法来获得我想要的结果。有人有一个好的解决方案吗?

+3

这是非常有帮助的学习为要执行的操作的术语。在这种情况下,您正在尝试查找列表的产品。看看这个:http://stackoverflow.com/questions/8217764/cartesian-product-of-two-lists – Marcin 2012-08-03 21:23:59

+0

@Marcin谢谢你。我发现在学习任何程度的函数式编程时遇到的最大绊脚石之一是挑选新的术语。 – KChaloux 2012-08-03 21:41:16

+0

跨产品?与笛卡尔产品相同?如果Spark在这里相关,那么[这个答案](http://stackoverflow.com/a/26565173/1175496)也是相关的 – 2016-07-22 07:44:38

回答

20

如何:

val pairs = for(x <- nums; y <- nums) yield (x, y) 
+0

壮观地工作。我不完全确定*为什么*它的工作原理。对于(x < - nums)for(y < - nums)',for(x < - nums; y < - nums)就像是一种简洁的方式吗? (#)(#)(#) – KChaloux 2012-08-03 21:44:26

+6

@KChaloux:它是'nums.flatMap(x => nums.map((x,_)))',它本质上是'nums.map(x => nums.map((x,_))的语法糖) ).flatten',如果有帮助的话。 – 2012-08-03 21:53:31

+0

@dbyrne这绝对是我可以使用的洞察力。 – KChaloux 2012-08-03 22:09:03

1

下面是另一个版本使用地图和扁平

val pairs = nums.flatMap(x => nums.map(y => (x,y)))

List[(Int, Int)] = List((1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (3,5), (4,1), (4,2), (4,3), (4,4), (4,5), (5,1), (5,2) (5,3), (5,4), (5,5))

这可以很容易地裹成composePairs功能,如果你喜欢:

def composePairs(nums: Seq[Int]) = 
    nums.flatMap(x => nums.map(y => (x,y))) 
+2

更好的方法是使用'flatMap(...)'而不是'map(...)。flatten'。 – 2012-08-04 10:58:16

2

对于那些你不想重复谁:

val uniquePairs = for { 
     (x, idxX) <- nums.zipWithIndex 
     (y, idxY) <- nums.zipWithIndex 
     if idxX < idxY 
    } yield (x, y) 

val nums = List(1,2,3,4,5) 
uniquePairs: List[(Int, Int)] = List((1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)) 
+0

你想'<='。你的输出缺少(例如)'(1,1)' – 2017-08-17 20:48:23

+0

在某些情况下,可能会看到'(x,x)'重复。将'<='或替换为'>','> ='应该是显而易见的。 – keos 2017-08-18 02:43:29