假设我想做类似的事情:
dict
.values()
.map(fun scrub/1)
.flatMap(fun split/1)
.groupBy(fun keyFun/1, fun count/1)
.to_dict()
在Erlang中实现这一目标最优雅的方法是什么?
答案 0 :(得分:3)
没有直接的简单方法。我看到的所有尝试看起来都比简单的构图更糟糕。如果您将查看Erlang中的大多数开源项目,您会发现它们使用通用组合。重用你的例子:
to_dict(
groupBy(fun keyFun/1, fun count/1,
flatMap(fun split/1,
map(fun scrub/1,
values(dict))))).
答案 1 :(得分:2)
这不是Erlang中自然的构造。如果你有几个功能,我会使用常规的作文:
lists:flatten(lists:map(fun (A) ->
do_stuff(A)
end,
generate_list())).
对于更长的一系列操作,中间变量:
Dict = #{hello => world, ...},
Values = maps:values(Dict),
ScrubbedValues = lists:map(fun scrub/1, Values),
SplitValues = lists:flatten(lists:map(fun split/1, ScrubbedValues)),
GroupedValues = basil_lists:group_by(fun keyFun/1, fun count/1, SplitValues),
Dict2 = maps:from_list(GroupedValues).
如果您希望将所有这些操作组合在一起,那将是什么样子。
但是,我更有可能以不同的方式写这个:
-spec remap_values(map()) -> map().
remap_values(Map) ->
map_values(maps:values(Map)).
-spec map_values(list()) -> map().
map_values(Values) ->
map_values(Values, [], []).
-spec map_values(list(), list(), list()) -> map().
map_values([], OutList, OutGroup) ->
%% Base case: transform into a map
Grouped = lists:zip(OutGroup, OutList),
lists:foldl(fun ({Group, Element}, Acc = #{Group := Existing}) ->
Acc#{Group => [Element | Existing]};
({Group, Element}, Acc) ->
Acc#{Group => [Element]}
end,
#{},
Grouped;
map_values([First|Rest], OutList, OutGroup) ->
%% Recursive case: categorize process the first element and categorize the result
Processed = split(scrub(First)),
Categories = lists:map(fun categorize/1, Processed),
map_values(Rest, OutList ++ Processed, OutGroup ++ Categories).
实际的正确实现很大程度上取决于代码的运行方式 - 我在这里写的内容非常简单,但在大量数据上可能效果不佳。如果你真的想要处理无穷无尽的数据流,你需要自己编写(尽管你可能会发现Gen Server是一个非常有用的框架)。