如何通过这种方式比较元素来组合两个列表?

时间:2017-01-25 15:35:35

标签: list function haskell

我刚刚开始学习Haskell,我必须创建一个函数composite,它接收两个列表a, b :: [(String, String)]作为输入,并输出一个新的列表c :: [(String, String)],这是一个ab的'组合'。具体而言,列表c必须仅包含(p,q)对,其中r为:{/ p>

  • (p,r)位于a
  • {li> (r,q)位于b

例如:

  • composite [("1","2")] [("2","3"), ("2","4")] == [("1","3"), ("1","4")]
  • composite [("1","2"), ("5","2")] [("2","3"), ("2","4")] == [("1","3"), ("1","4"), ("5","3"), ("5","4")]
  • composite [("1","2"), ("1","4"), ("1","5")] [("2","3"), ("4","3")] == [("1","3")]

我该怎么做?

2 个答案:

答案 0 :(得分:4)

您可以使用列表推导在多个列表中组合列表:

[(x,z)|(x,y) <- a, (y',z) <- b, y == y' ]

请注意,结果是(x,z)元组的列表,输入是(x,y)(y,z)元组的列表。

我已在http://tryhaskell.org中使用您的列表测试用例尝试了此操作;可以随意复制粘贴并随意使用它:

[(x,z) | (x,y) <-[('a', 'b'), ('a', 'd'), ('a', 'e')],(y',z) <- [('b','c'), ('d','c')], y == y']

这会产生:

  

[(&#39; A&#39;&#39; C&#39),(&#39; A&#39;&#39; C&#39)]

还有一些其他注意事项。

首先是y == y'。正如@chi指出的那样,如果你使用&#39; y&#39;再次在列表理解中,系统不会将其视为相同的变量。您需要使用新变量y'(或任何其他名称)并明确告诉Haskell yy'应具有相同的值。

其次,我们不使用大写字母; Haskell区分大小写,并将大写字母用于其他目的。

第三,你不必只为Strings制作它。该函数可以对任意类型的元组进行操作:

composite :: [(a,a)] -> [(a,a)] -> [(a,a)]  

正如@Daniel Wagner在评论中所指出的,它实际上有点复杂:

composite :: (Eq a) => [(a,a)] -> [(a,a)] -> [(a,a)] 

Eq a告诉Haskell a是可以比较平等的东西。形式上,aEq类型类的成员。 他还观察到我们可以进一步概括:列表A中元组的左侧不必与列表B中元组右侧的类型相同。例如,您可以使用(Int,String)列表和(String,Char)列表,并在字符串上匹配它们。类型将变为:

composite :: Eq b => [(a, b)] -> [(b, c)] -> [(a, c)]

最后要注意的是,结果列表中可能存在重复项。在您的第三个测试用例中就是这种情况。

这项练习可能并不需要你删除重复的内容..
Haskells库提供了删除重复项的工具。在生产环境中,您应该使用这些工具。但是在学习时,编写自己的代码以删除重复项可能是一项有用的练习。

我也在ideone.org得到了它。不要担心&#34;主要&#34;和&#34;打印&#34;那边现在;只是试验一下这个功能,看看你是否理解它。

答案 1 :(得分:3)

S.L. Barth走在正确的轨道上,但并非如此。你需要做的是通过两个列表的笛卡尔积,比较y部分,如果它们匹配,那么你可以在输出上发出一个元组。

这可以通过list comprehension轻松完成,例如:

[(x, z) | (x, y1) <- a, (y2, z) <- b, y1 == y2]

你应该可以将它包装在一个函数中。

请注意,如果您希望函数具有多态性,则其类型需要Eq y约束,以便您可以实际比较y部分:

composite :: Eq y => [(x, y)] -> [(y, z)] -> [(x, z)]