[erlang-questions] Merging maps with a fun like dict:merge/3

Michael Truog mjtruog@REDACTED
Wed Aug 26 22:21:03 CEST 2015


A straight-forward way to provide a maps merge function based on the dict documentation is:

maps_update(K, F, V0, Map) ->
     try maps:get(K, Map) of
         V1 ->
             maps:put(K, F(V1), Map)
     catch
         error:{badkey, K} ->
             maps:put(K, V0, Map)
     end.

maps_merge(Fun, Map1, Map2) ->
     maps:fold(fun (K, V1, Map) ->
                   maps_update(K, fun (V2) -> Fun(K, V1, V2) end, V1, Map)
               end, Map2, Map1).

Not sure about the speed compared to the code below, but both results should be the same if everything is working properly.

On 08/26/2015 11:44 AM, Ivan Uemlianin wrote:
> Dear Alexander, Hynek
>
> That is a *lot* faster! :D
>
> Thanks very much both.
>
> Ivan
>
>
> On 08/26/15 10:38, Ivan Uemlianin wrote:
>> Oh yes of course that's better.  Thanks
>>
>> Ivan
>>
>>
>> On 26/08/2015 10:32, Hynek Vychodil wrote:
>>> I would consider:
>>>
>>> merge_ap(F, [Head | Tail]) ->
>>>     lists:foldl(fun(Y, X) ->
>>> maps:merge(X, maps:map(fun(Key, Value) ->
>>>  case maps:find(Key, X) of
>>>    {ok, V} -> F(Key, V, Value);
>>>    error    -> Value
>>>  end
>>>                                                end,
>>>                                                Y))
>>>                 end,
>>>                 Head,
>>>                 Tail).
>>>
>>> On Wed, Aug 26, 2015 at 10:45 AM, Ivan Uemlianin <ivan@REDACTED> wrote:
>>>
>>>     Dear Alexander
>>>
>>>     Thanks!  That looks excellent!
>>>
>>>     I notice that your function F is different from the dict:merge/3 function: instead of taking a key and the two values, is takes two values, defaulting the first to 0.
>>>
>>>     I've put my case clause into your framework:
>>>
>>>     merge_ap(F, [Head | Tail]) ->
>>>         lists:foldl(fun(Y, X) ->
>>>     maps:merge(X, maps:map(fun(Key, Value) ->
>>>     case maps:is_key(Key, X) of
>>>     false ->
>>>     Value;
>>>     true ->
>>>     F(Key, Value, maps:get(Key, X))
>>>     end
>>>     end,
>>>                                                    Y))
>>>                     end,
>>>                     Head,
>>>                     Tail).
>>>
>>>     This has desired behaviour, and will probably still perform well.  Using lists:foldl is a brilliant idea.
>>>
>>>     Best wishes
>>>
>>>     Ivan
>>>
>>>
>>>
>>>     On 26/08/2015 09:16, Alexander Petrovsky wrote:
>>>>     Hi!
>>>>
>>>>     I've make some little benchmarks, and noticed that the most effective way is:
>>>>
>>>>     merge(F, [Head | Tail]) ->
>>>>         lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> F(maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail).
>>>>
>>>>
>>>>     2015-08-23 20:05 GMT+03:00 Ivan Uemlianin <ivan@REDACTED>:
>>>>
>>>>         Dear All
>>>>
>>>>         The maps module does not have a merge/3 like dict:merge/3, which calls a function fun(Key, Val1, Val2) when both dicts have the same key.  From the documentation, "If a key occurs in both dictionaries then Fun is called with the key and both values to return a new value."
>>>>
>>>>         The dict documentation says that dict:merge/3 is faster than an equivalent implemented in erlang.
>>>>
>>>>         http://www.erlang.org/doc/man/dict.html#merge-3
>>>>
>>>>         Why does the maps module not have a similar merge/3?  Is it because writing our own erlang implementation is at fast as it gets?
>>>>
>>>>         Below is an implementation which seems to work.  Can it be made faster?
>>>>
>>>>
>>>>         merge_maps(Fun, M1, M2) ->
>>>>         maps:fold(fun(K, V1, Acc) ->
>>>>                               case maps:is_key(K, Acc) of
>>>>                                   false ->
>>>>         maps:put(K, V1, Acc);
>>>>                                   true ->
>>>>                                       V2 = maps:get(K, Acc),
>>>>         maps:put(K, Fun(K, V1, V2), Acc)
>>>>                               end
>>>>                       end,
>>>>                       M1,
>>>>                       M2).
>>>>
>>>>         merge_maps_test() ->
>>>>             merge_maps(fun(_K, V1, V2) -> V1 + V2 end,
>>>>                        #{a => 1, b => 2, c => 3},
>>>>                        #{b => 2, c => 3, d => 4}) =:=
>>>>                 #{a => 1, b => 4, c => 6, d => 4}.
>>>>
>>>>
>>>>         With thanks and best wishes
>>>>
>>>>         Ivan
>>>>
>>>>         -- 
>>>>         ============================================================
>>>>         Ivan A. Uemlianin PhD
>>>>         Llaisdy
>>>>         Speech Technology Research and Development
>>>>
>>>>         ivan@REDACTED
>>>>                                 @llaisdy
>>>>         llaisdy.wordpress.com <http://llaisdy.wordpress.com>
>>>>         github.com/llaisdy <http://github.com/llaisdy>
>>>>         www.linkedin.com/in/ivanuemlianin
>>>>
>>>>                                 festina lente
>>>>         ============================================================
>>>>
>>>>         _______________________________________________
>>>>         erlang-questions mailing list
>>>>         erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>>>>         http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>>>
>>>>
>>>>
>>>>     -- 
>>>>     Петровский Александр / Alexander Petrovsky,
>>>>
>>>>     Skype: askjuise
>>>>     Phone: +7 914 8 820 815
>>>>
>>>
>>>     -- 
>>>     ============================================================
>>>     Ivan A. Uemlianin PhD
>>>     Llaisdy
>>>     Speech Technology Research and Development
>>>
>>>                          ivan@REDACTED  <mailto:ivan@REDACTED>
>>>                              @llaisdy
>>>                               llaisdy.wordpress.com  <http://llaisdy.wordpress.com>
>>>                    github.com/llaisdy  <http://github.com/llaisdy>
>>>                           www.linkedin.com/in/ivanuemlianin  <http://www.linkedin.com/in/ivanuemlianin>
>>>
>>>                              festina lente
>>>     ============================================================
>>>
>>>
>>>     _______________________________________________
>>>     erlang-questions mailing list
>>>     erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>>>     http://erlang.org/mailman/listinfo/erlang-questions
>>>
>>>
>>
>> -- 
>> ============================================================
>> Ivan A. Uemlianin PhD
>> Llaisdy
>> Speech Technology Research and Development
>>
>>                      ivan@REDACTED
>>                          @llaisdy
>>                           llaisdy.wordpress.com
>>                github.com/llaisdy
>>                       www.linkedin.com/in/ivanuemlianin
>>
>>                          festina lente
>> ============================================================
>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-questions
>
> -- 
> ============================================================
> Ivan A. Uemlianin PhD
> Llaisdy
> Speech Technology Research and Development
>
>                      ivan@REDACTED
>                          @llaisdy
>                           llaisdy.wordpress.com
>                github.com/llaisdy
>                       www.linkedin.com/in/ivanuemlianin
>
>                          festina lente
> ============================================================
>
>
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20150826/bc2d64dc/attachment.htm>


More information about the erlang-questions mailing list