2016-08-22 59 views
2

假设我想做的事是这样的:什么是Erlang的流操作方法?

dict 
    .values() 
    .map(fun scrub/1) 
    .flatMap(fun split/1) 
    .groupBy(fun keyFun/1, fun count/1) 
    .to_dict() 

什么是最优雅的方式在二郎山实现这一目标?

+0

奇怪的是,这是一个构造,我很少需要在我的真实代码中。我可能会在dict上做一次地图操作。 – rvirding

回答

3

没有直接简单的方法做到这一点。我看到的所有尝试看起来都比简单的作文更差。如果你将看Erlang的大部分开源项目,你会发现他们使用通用组合。重新使用你的例子:

to_dict(
groupBy(fun keyFun/1, fun count/1, 
flatMap(fun split/1, 
map(fun scrub/1, 
values(dict))))). 
+0

谢谢。虽然这可惜了:( – BasilTomato

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是一个非常有用的框架)。