在地图中找到最小值

时间:2015-05-17 23:34:43

标签: erlang

我有一个如下组织的地图。键是一个简单的术语,比如说一个整数,但值是复数元组{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来找到折叠的初始值,但我想知道是否有更好的方法或其他数据结构。

- 感谢。

2 个答案:

答案 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计算最小值。