我有以下项目清单
[{id, user1, category1}, {id, user2, category1}, {id, user1, category2}....],
其中id是唯一的,用户/类别可以重复。我试图弄清楚如何从列表中获取统计数据,例如
[{user1, category1, 20}, {user1, category2, 30}..]
答案 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
会更快。换句话说,列表与地图的大小有关。