feat: Add map:zipfold (#37)

This commit is contained in:
Yaroslav Rogov 2021-09-27 19:16:22 +03:00 committed by GitHub
parent b08ef4d61e
commit 82c5ff3866
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 0 deletions

View File

@ -19,6 +19,7 @@
-export([diff/2]).
-export([fold_while/3]).
-export([search/2]).
-export([zipfold/4]).
%%
@ -176,3 +177,25 @@ do_search(Fun, {Key, Value, Iter}) ->
true -> {Key, Value};
false -> do_search(Fun, maps:next(Iter))
end.
%% @doc Fold two maps "joining" them by key.
%% NOTE: If a key-value exists only in one map, this pair is ignored altogether
-spec zipfold(
fun((K, V1, V2, A) -> A),
InitAcc :: A,
#{K => V1},
#{K => V2}
) -> A.
zipfold(Fun, Acc, M1, M2) ->
maps:fold(
fun(Key, V1, AccIn) ->
case maps:find(Key, M2) of
{ok, V2} ->
Fun(Key, V1, V2, AccIn);
error ->
AccIn
end
end,
Acc,
M1
).

View File

@ -57,6 +57,63 @@ prop_search_not_found() ->
end
).
-spec prop_zipfold() -> proper:test().
prop_zipfold() ->
?FORALL(
[Left, Right],
[map(), map()],
begin
CommonKeys = maps_common_keys(Left, Right),
Actual =
genlib_map:zipfold(
fun(Key, LValue, RValue, Acc) -> Acc#{Key => {LValue, RValue}} end,
#{},
Left,
Right
),
Expected =
maps_merge_with(
fun(_Key, LValue, RValue) -> {LValue, RValue} end,
Left,
Right
),
Actual =:= maps:with(CommonKeys, Expected)
end
).
-if(?OTP_RELEASE >= 24).
maps_merge_with(Combiner, Left, Right) ->
maps:merge_with(Combiner, Left, Right).
-else.
maps_merge_with(Combiner, Left, Right) ->
CommonMerged =
lists:foldl(
fun(Key, Acc) ->
Acc#{Key => Combiner(Key, maps:get(Key, Left), maps:get(Key, Right))}
end,
#{},
maps_common_keys(Left, Right)
),
maps:merge(maps:merge(Left, Right), CommonMerged).
%% END -if(?OTP_RELEASE >= 24).
-endif.
maps_common_keys(LeftMap, RightMap) ->
sets:to_list(
sets:intersection(
sets:from_list(maps:keys(LeftMap)),
sets:from_list(maps:keys(RightMap))
)
).
map() ->
?LET(KVList, list({term(), term()}), maps:from_list(KVList)).