合并匹配元素的列表

时间:2017-02-10 17:42:15

标签: haskell

我编写了一个合并两对列表的函数,在这种情况下,每个元素都包含一个字符和一个数字。

mergeTupleList [] blist = blist
mergeTupleList alist [] = []
mergeTupleList (a:ab:as) (b:bn:bs) =
    if ab == b
        then a:[] ++ bn:[] ++ mergeTupleList (a:ab:as) (bs)
        else [] ++ mergeTupleList (as) (b:bn:bs)

listA = [('a',1),('b',1),('a',2),('b',1)] 
listZ = [('b',1),('z',1),('b',1),('z',2)]

似乎在'else'情况下(b:bn:bs)不是开头加载的整个对列表,而是短版本(bs),因为它已经被'then'条件过滤了。 我正在寻找一种方法将原始(b:bn:bs)列表传输到此函数。

输入和输出:

*Main> mergeTupleList ListA ListZ
[('a',1),('z',1),('a',1),('z',2)]

预期产出:

[('a',1),('z',1),('a',1),('z',2),('a',2),('z',1),('a',2),('z',2)]

澄清:

  

也许合并不是一个充分的词。对于原始ListA中存在的ListZ中的每个(第二个)元素,请在其后面写入元素。

另一个例子:

ListA = [1,0,3,0]
ListZ = [0,8,0,9]

*Main> mergeTupleList listA listZ 
[1,8,1,9]

预期产量: [1,8,1,9,3,8,3,9]

2 个答案:

答案 0 :(得分:1)

我有一系列的解决方案。首先,以下产生所需的输出。我认为这是指定的,但请注意mergeTupleList' 不再在它的第一行返回bList。虽然你的描述让我相信你确实想要那样,但这并没有达到预期的效果。

此解决方案的秘诀在于包含子函数tupleAB,该函数会为第一个a:ab执行所有tupling,在评估下一个bs之前使用整个ab列表}}对整个bs列表。

mergeTupleList' [] _ = []
mergeTupleList' alist [] = []
mergeTupleList' (a:ab:as) bbnbs =
  let
    tupleAB (b:bn:bs) = 
      if ab == b
         then a:[] ++ bn:[] ++ tupleAB bs 
         else [] ++ tupleAB bs 
    tupleAB _ = []
  in tupleAB bbnbs ++ mergeTupleList' as bbnbs 

接下来是对所有顽皮:[] ++

的轻微清理
mergeTupleList'' [] _ = []
mergeTupleList'' alist [] = []
mergeTupleList'' (a:ab:as) bbnbs =
  let
    tupleAB (b:bn:bs) = 
      if ab == b
         then a : bn : tupleAB bs 
         else tupleAB bs 
    tupleAB _ = []
  in tupleAB bbnbs ++ mergeTupleList'' as bbnbs 

以上解决方案有一些悬空的案例表达。如果其中一个列表没有编号,我们该怎么办?如果我们将每个前两个项转为一对,我们就有成对的列表(对)。此转换功能会更改您的列表。

pairListCvt :: [a] -> [(a,a)]
pairListCvt (a:b:cs) = (a,b) : pairListCvt cs
pairListCvt (a:[]) = [] --maybe should be error?
pairListCvt _ = []

listACvt = pairListCvt listA 
listZCvt = pairListCvt listZ

现在,再次重写,我们的模式不太匹配,因此错误的可能性更小。这是选择类型以提供一点安全性的示例;类型安全。

mergeTupleList''' [] _ = []
mergeTupleList''' alist [] = []
mergeTupleList''' ((a,ab):as) bbnbs =
  let
    tupleAB ((b,bn):bs) = 
      if ab == b
         then (a , bn) : tupleAB bs 
         else mergeTupleList''' as ((b,bn):bs)
    tupleAB _ = []
  in tupleAB bbnbs ++ mergeTupleList''' as bbnbs 

接下来,由于我们使用alist中的每个字词来创建来自blist的字词, 我在这里使用map

mergeTupleList'''' as bbns = 
  let
    tupleAB ((b,bn):bs) (a,ab) = 
      if ab == b
         then (a, bn) : tupleAB bs (a,ab)
         else tupleAB bs (a,ab)
    tupleAB [] _ = []
  in concat $ map (tupleAB bbns) as

最后,内部tupleAB可以表示为fold;通过列表的逐元素分解逐步构建数据结构的东西。该折叠的核心逻辑现在保存在f

mergeTupleList''''' as bbns = 
  let
    tupleAB bs aab = foldr (f aab) [] bs
    f (a,ab) (b,bn) acc
       | ab == b        = (a,bn) : acc
       | otherwise      = acc
  in concat $ map (tupleAB bbns) as

我喜欢在哪里绑定,以便在风格上进行绑定。 Alghouth有关于选择的记忆性能问题我不明白。

mergeTupleListW as bbns = concat $ map (tupleAB bbns) as
  where
    tupleAB bs aab = foldr (f aab) [] bs
    f (a,ab) (b,bn) acc
       | ab == b        = (a,bn) : acc
       | otherwise      = acc

额外信用。他是作为List monad编写的函数。

mergeTupleListM as bbns = 
  do a <- as
     tupleAB bbns a
  where
    tupleAB bs aab = foldr (f aab) [] bs
    f (a,ab) (b,bn) acc
       | ab == b        = (a,bn) : acc
       | otherwise      = acc

答案 1 :(得分:0)

这个问题已经得到了回答,但是在评论的帮助下,这是我想出来的。 首先,我们创建一个groupByTwo函数来打破包含每两个元素的列表中的listA

groupByTwo [] = []
groupByTwo list = 
 (take 2 list) : (groupByTwo (drop 2 list))

然后我们创建一个mergeTupleList'函数来在列表列表的每个元素上运行简单的mergeTupleList

mergeTupleList' [] _ = []
mergeTupleList' (a:as) list2 =
  mergeTupleList a list2 ++ mergeTupleList' as list2

最后,第三个函数叫groupTupleMerge,让生活更轻松。

groupTupleMerge list1 list2 =
    mergeTupleList' (groupByTwo list1) list2