我有一个如下组织的地图。键是一个简单的术语,比如说一个整数,但值是复数元组{BB,CC,DD}。在地图中找到最小CC的最佳方法是什么?到目前为止,我有以下
-module(test).
-author("andre").
%% API
-export([init/0]).
init() ->
TheMap = build(maps:new(), 20),
io:format("Map: ~p~n", [TheMap]),
AKey = hd(maps:keys(TheMap)),
AValue = maps:get(AKey, TheMap),
maps:fold(fun my_min/3, {AKey, AValue}, TheMap).
build(MyMap, Count) when Count == 0 ->
MyMap;
build(MyMap, Count) ->
NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),
build(NewMap, Count - 1).
my_min(Key, {A,B,C}, {MinKey, {AA,BB,CC}}) ->
if B < BB -> {Key, {A,B,C}};
B >= BB -> {MinKey, {AA,BB,CC}}
end.
我的地图很小,所以我不太担心使用AKey和AValue来找到折叠的初始值,但我想知道是否有更好的方法或其他数据结构。
- 感谢。
答案 0 :(得分:2)
你所拥有的是一个很好的解决方案,但它可以得到改善。没有必要挖出第一个键和值来使用折叠的初始值,因为您只需传递一个人工值并使折叠函数处理它。此外,您可以改进函数头中模式匹配的使用。最后,使用start
而不是init
,因为这样可以在从命令行调用erl
时更容易调用。
以下是改进版本:
-module(test).
-author("andre").
%% API
-export([start/0]).
start() ->
TheMap = build(maps:new(), 20),
io:format("Map: ~p~n", [TheMap]),
maps:fold(fun my_min/3, {undefined, undefined}, TheMap).
build(MyMap, 0) ->
MyMap;
build(MyMap, Count) ->
NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),
build(NewMap, Count - 1).
my_min(Key, Value, {undefined, undefined}) ->
{Key, Value};
my_min(Key, {_,B,_}=Value, {_, {_,BB,_}}) when B < BB ->
{Key, Value};
my_min(_Key, _Value, Acc) ->
Acc.
my_min/3
折叠函数有三个子句。第一个匹配特殊起始值{undefined, undefined}
,并返回新累加器值,无论它传递的是{Key, Value}
。这样做的好处不仅在于您在开始折叠之前避免了特殊处理,而且如果地图为空,您将获得特殊值{undefined, undefined}
作为结果,您可以相应地处理它。第二个子句使用guard来检查值的B
是否小于fold累加器中的BB
值,如果是,则返回{Key, Value}
作为新的累加器值。 final子句只返回现有的累加器值,因为只有大于或等于现有累加器中的值才会调用此子句。
您可能还会考虑使用一个简单的键/值元组列表,因为对于少量元素,它可能优于地图。如果你的测量表明你应该使用一个列表,那么类似的折叠也适用于它。
答案 1 :(得分:0)
-module(test).
-author("andre").
%% API
-export([init/0]).
init() ->
TheMap = build(maps:new(), 24),
io:format("Map: ~p~n", [TheMap]),
List = maps:to_list(TheMap),
io:format("List: ~p~n", [List]),
Fun = fun({_, {_, V1, _}} = Element, {_, {_, V2, _}}) when V1 < V2 ->
Element;
(_, Res) ->
Res
end,
Res = lists:foldl(Fun, hd(List), tl(List)),
io:format("Res: ~p~n", [Res]).
build(MyMap, Count) when Count == 0 ->
MyMap;
build(MyMap, Count) ->
NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),
build(NewMap, Count - 1).
您可以使用maps:to_list/1将地图转换为列表,然后使用lists:foldl/3计算最小值。