在应用场景中,我们经常需要对 tuple 组成的lists进行分组,本文参考网上的方案,实现了多元组的group by。
1. 原生版本(来自网络,原文链接已找不到,如果有线索,请联系本人)
源码:
group_by([])->
[];
group_by(KVList) ->
Fun = fun({K,V}, D) -> dict:append(K, V, D) end,
dict:to_list(lists:foldr(Fun , dict:new(), KVList)).
测试:L = [{1,2},{1,4},{2,5},{5,6}],group_by(L) .
输出:[{2,[5]},{5,[6]},{1,[4,2]}].
原生版本只支持二元组组成的lists,而且key 一定在元组中的第一个位置。当我们扩展到三元组组成的lists就行不通了。
2. 支持三(多)元组并且支持key在任意位置(不超过size大小)
group_by(KVList, Pos) when is_integer(Pos)->
Fun = fun(Item, D) ->
K = element(Pos, Item),
case erlang:delete_element(Pos, Item) of
{V} ->
dict:append(K, V, D);
V ->
dict:append(K, V, D)
end
end,
dict:to_list(lists:foldr(Fun , dict:new(), KVList)).
测试代码:z_lib:group_by([{1,2,3}, {2,3,4}, {4,5,6}, {1,3,7}],2).
输出:[{3,[{1,7},{2,4}]},{2,[{1,3}]},{5,[{4,6}]}]
扩展版本满足了三(多)元组并支持key在任意位置,但是如果我们希望可以对两个key进行group by 怎么办呢?下面的版本就是
要做这件事情。
3. 支持2个key嵌套group by,以两个key的情况举例:
group_by([], _, _) ->
[];
group_by(KVList, Pos1, Pos2) when Pos1 =:= Pos2 ->
group_by(KVList, Pos1);
group_by(KVList, Pos1, Pos2) when Pos1 < Pos2 ->
[ {K, group_by(V, Pos2-1)} || {K, V} <- group_by(KVList, Pos1)];
group_by(KVList, Pos1, Pos2) ->
[ {K, group_by(V, Pos2)} || {K, V} <- group_by(KVList, Pos1)].
测试代码:z_lib:group_by([{1,2,3}, {2,3,4}, {4,5,6}, {1,3,7}], 2,3).
结果输出:[{3,[{4,[2]},{7,[1]}]},{2,[{3,[1]}]},{5,[{6,[4]}]}].
根据上面的思路,很容易扩展到多个key排序的情况。