erlang:计算元组列表中的项目

时间:2016-09-19 15:36:53

标签: erlang

我有以下项目清单 [{id, user1, category1}, {id, user2, category1}, {id, user1, category2}....], 其中id是唯一的,用户/类别可以重复。我试图弄清楚如何从列表中获取统计数据,例如

[{user1, category1, 20}, {user1, category2, 30}..]

2 个答案:

答案 0 :(得分:3)

你可以使用列表来实现:foldl / 3功能。

F = fun({_,User,Cat},Accumulator) -> 
        N = maps:get({User,Cat},Accumulator,0),
        maps:put({User,Cat},N+1,Accumulator) end.
CountMap = lists:foldl(F,#{},InputListe),

这将返回#{{user1, category1} => 20, {user1, category2} => 30 ...}

形式的地图

如果你真的需要一个列表,那么你必须转换地图:

CountList = maps:fold(fun({User,Cat}, Count, Acc) -> [{User,Cat,Count}|Acc] end,[],CountMap).

我使用了中间映射,因为如果输入列表很大,那么它会提供快速访问和快速更新,直接与您在输出列表中工作的解决方案相比。检索列表中的信息(列表的平均分析一半)需要花费很多,修改它的成本也很高(平均复制列表的一半

对于200 000个元素的输入列表,生成地图需要94毫秒,并将其转换为笔记本电脑上的列表,以及500,000个元素的219毫秒。

答案 1 :(得分:3)

尽管Pascal's solution是一个很好的通用解决方案,但对于小型数据集(例如最多15 000个),您可以使用lists:sort/1使用此版本,这对他们来说要快得多。

main(L) ->
    count(lists:sort(transform(L))).

count([]) -> [];
count([H|T]) ->
    count(H, T, 1, []).

count(H, [H|T], N, Acc) -> count(H, T, N+1, Acc);
count({U, C}, [H|T], N, Acc) -> count(H, T, 1, [{U, C, N}|Acc]);
count({U, C}, [], N, Acc) -> [{U, C, N}|Acc].

transform(L) ->
    transform(L, []).

transform([], Acc) -> Acc;
transform([{_, User, Category}|T], Acc) ->
    transform(T, [{User, Category}|Acc]).

修改

确定哪种算法更快的关键点是一系列唯一键。如果存在大数据集但具有少量唯一{User, Category},则使用地图的解决方案将更快。如果相反,lists:sort/1会更快。换句话说,列表与地图的大小有关。