合并列表erlang的内部列表

时间:2014-02-19 09:41:29

标签: list merge erlang

我有一个列表 L

L = [L1, L2, L3,...]. 

其中L1,L2,L3 ..本身就是列表,如下所示:

L1 = [{k1, 10}, {k2, 20}, {k3, 30}, {k4, 20.9}, {k6, "Hello world"}]

L2 = [{k1, 90}, {k2, 210}, {k3, 60}, {k4, 66.9}, {k6, "Hello universe"}]

L3 = [...]

现在我想要一个结果组合列表:

FinalList = [
       {k1, [10, 90, ...]}, % '...' denotes values from other lists
       {k2, [20, 210, ...]},
       {K3, [30, 60, ...]},
       {k4, [20.9, 66.9, ...]},
       {K6, ["Hello world", "Hello universe", ...]}
     ]

我可以使用我的Old Posts Solutions:Combine/Merge Two Erlang lists进行合并但是我不确定如何将 L (列表列表)传递给该合并函数。

提前谢谢!

3 个答案:

答案 0 :(得分:3)

您可以使用lists:foldlmerge应用于列表列表。这是一个例子:

-module(test).
-export([test/0]).


merge(L1, L2) ->
    merge_(lists:sort(L1), lists:sort(L2)).

merge_([{K, V1}|T1], [{K, V2}|T2]) when is_list(V1), is_list(V2)
    -> [{K, V1 ++ V2}|merge_(T1, T2)]; 
merge_([{K, V1}|T1], [{K, V2}|T2]) when is_list(V1)
    -> [{K, V1 ++ [V2]}|merge_(T1, T2)];
merge_([{K, V1}|T1], [{K, V2}|T2]) when is_list(V2)
    -> [{K, [V1] ++ V2}|merge_(T1, T2)];
merge_([{K, V1}|T1], [{K, V2}|T2]) 
    -> [{K, [V1, V2]}|merge_(T1, T2)];
merge_([{K1, V1}|T1], [{K2, _}|_]=L2) when K1 < K2 
   -> [{K1, [V1]}|merge_(T1, L2)];
merge_(L1, [{K2, V2}|T2]) when is_list(V2)
   -> [{K2, V2}|merge_(L1, T2)];
merge_(L1, [{K2, V2}|T2]) 
   -> [{K2, [V2]}|merge_(L1, T2)];
merge_(L1, []) -> [{K, V} || {K, V} <- L1].


test() ->

  L1 = [{k1, 10}, {k2, 20}, {k3, 30}, {k4, 20.9}, {k6, "Hello world"}],
  L2 = [{k1, 90}, {k2, 210}, {k3, 60}, {k4, 66.9}, {k6, "Hello universe"}],
  L3 = [{k1, 45}, {k2, 35}, {k3, 37}, {k4, 77.9}, {k6, "Hello cosmo"}],
  lists:foldl(fun merge/2, [], [L1, L2, L3]).

结果如下:

36> test:test().
[{k1,"-Z\n"},
 {k2,[35,210,20]},
 {k3,[37,60,30]},
 {k4,[77.9,66.9,20.9]},
 {k6,"Hello cosmoHello universeHello world"}]

如您所见,

  1. 您需要修改merge函数来处理列表(不仅仅是原始问题中的原子)。它已在我的示例代码中完成,该代码基于Vychodil's answer

  2. 您需要修改merge函数以正确处理字符串(如键k1和k6中的证据)。你应该能够自己解决它。

  3. 最后但并非最不重要的是,你应该在解决问题时接受答案。检查this link了解原因。

答案 1 :(得分:3)

我得到了启发,并得到了这个功能,假设所有列表都有相同的键(这似乎是这里的情况):

merge_lists([First|_]=ListOfLists) ->
    Keys = proplists:get_keys(First),
    lists:map(fun(Key) ->
                  {key,lists:flatmap(fun(List) -> 
                                         [proplists:get_value(Key,List)] 
                                         end
                                    ,ListOfLists)} 
                  end
             ,Keys).

请原谅格式化:此函数首先获取它应该查找的键,然后按键编译每个列表中的值列表(不需要以这种方式更新累加器)。可能是一个单行,但这将是一个很长的路线;)

一些测试列表的结果(L3 = L1,但没有键k6,这就是未定义的原因):

1> test:merge_lists([L1,L3,L2]).
[{k1,"\n\nZ"},
 {k2,[20,20,210]},
 {k3,[30,30,60]},
 {k4,[20.9,20.9,66.9]},
 {k6,["Hello world",undefined,"Hello universe"]}]

编辑:这可能是一种更容易理解的格式。看起来也更好:

merge_lists([First|_]=ListOfLists) ->
    MapKeys = fun(Key) -> 
                MapLists = fun(List) -> [proplists:get_value(Key,List)] end,
                Values   = lists:flatmap(MapLists ,ListOfLists),
                {Key,Values} end,
    lists:map(MapKeys,proplists:get_keys(First)).

答案 2 :(得分:2)

Berzemus对相关问题的回答很容易适应:

merge(ListOfLists) ->
    Combined = lists:append(ListOfLists),
    Fun      = fun(Key) -> {Key,proplists:get_all_values(Key,Combined)} end,
    lists:map(Fun,proplists:get_keys(Combined)).

但是,如果L中有许多列表或者它们很长,那么效率会非常低。在这种情况下,您应该从Vychodil的解决方案开始。