Home:ALL Converter>Find the minimum value in a map

Find the minimum value in a map

Ask Time:2015-05-18T07:34:43         Author:7Grok

Json Formatter

I have a map organized as follows.Key is a simple term lets say an integer but the value is complex tuple {BB,CC,DD}. What is the best way to find the minimum CC in the map ? So far I have the following

-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.

My map is small so I am not too worried about the usage of AKey and AValue to find initial values for the fold, but I was wondering if there was a better way, or other data structure.

-- Thanks.

Author:7Grok,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/30293209/find-the-minimum-value-in-a-map
Steve Vinoski :

What you have is close to a good solution, but it can be improved. There's no need to dig out the first key and value to use an the initial value for the fold, since you can just pass an artificial value instead and make your fold function deal with it. Also, you can improve your use of pattern matching in function heads. Lastly, use start instead of init since that makes it easier to invoke when calling erl from the command line.\n\nHere's an improved version:\n\n-module(test).\n-author(\"andre\").\n\n%% API\n-export([start/0]).\n\nstart() ->\n TheMap = build(maps:new(), 20),\n io:format(\"Map: ~p~n\", [TheMap]),\n maps:fold(fun my_min/3, {undefined, undefined}, TheMap).\n\nbuild(MyMap, 0) ->\n MyMap;\nbuild(MyMap, Count) ->\n NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),\n build(NewMap, Count - 1).\n\nmy_min(Key, Value, {undefined, undefined}) ->\n {Key, Value};\nmy_min(Key, {_,B,_}=Value, {_, {_,BB,_}}) when B < BB ->\n {Key, Value};\nmy_min(_Key, _Value, Acc) ->\n Acc.\n\n\nThe my_min/3 fold function has three clauses. The first matches the special start value {undefined, undefined} and returns as the new accumulator value whatever {Key, Value} it was passed. The benefit of this is not only that you avoid special processing before starting the fold, but also that if the map is empty, you'll get the special value {undefined, undefined} as the result and you can handle it accordingly. The second clause uses a guard to check if B of the value is less than the BB value in the fold accumulator, and if it is, return {Key, Value} as the new accumulator value. The final clause just returns the existing accumulator value, since this clause is called only for values greater than or equal to that in the existing accumulator.\n\nYou might also look into using a simple list of key/value tuples, since for a small number of elements it might outperform a map. If your measurements indicate you should use a list, a similar fold would work for it as well.",
2015-05-18T01:05:03
yy