Skip to content

Commit 2410811

Browse files
authored
Add Map.intersect/2 and Map.intersect/3 (#12336)
1 parent bc0cf0b commit 2410811

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

lib/elixir/lib/map.ex

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,44 @@ defmodule Map do
11491149
end
11501150
end
11511151

1152+
@doc """
1153+
Intersects two maps, returning a map with the common keys.
1154+
1155+
The values in the returned map are the values of the intersected keys in `map2`.
1156+
1157+
Inlined by the compiler.
1158+
1159+
## Examples
1160+
1161+
iex> Map.intersect(%{a: 1, b: 2}, %{b: "b", c: "c"})
1162+
%{b: "b"}
1163+
1164+
"""
1165+
@doc since: "1.15.0"
1166+
@spec intersect(map, map) :: map
1167+
defdelegate intersect(map1, map2), to: :maps
1168+
1169+
@doc """
1170+
Intersects two maps, returning a map with the common keys and resolving conflicts through a function.
1171+
1172+
The given function will be invoked when there are duplicate keys; its
1173+
arguments are `key` (the duplicate key), `value1` (the value of `key` in
1174+
`map1`), and `value2` (the value of `key` in `map2`). The value returned by
1175+
`fun` is used as the value under `key` in the resulting map.
1176+
1177+
## Examples
1178+
1179+
iex> Map.intersect(%{a: 1, b: 2}, %{b: 2, c: 3}, fn _k, v1, v2 ->
1180+
...> v1 + v2
1181+
...> end)
1182+
%{b: 4}
1183+
"""
1184+
@doc since: "1.15.0"
1185+
@spec intersect(map, map, (key, value, value -> value)) :: map
1186+
def intersect(map1, map2, fun) when is_function(fun, 3) do
1187+
:maps.intersect_with(fun, map1, map2)
1188+
end
1189+
11521190
@doc false
11531191
@deprecated "Use Map.new/2 instead (invoke Map.from_struct/1 before if you have a struct)"
11541192
def map(map, fun) when is_map(map) do

lib/elixir/test/elixir/keyword_test.exs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ defmodule KeywordTest do
2121
end
2222

2323
test "implements (almost) all functions in Map" do
24-
assert Map.__info__(:functions) -- Keyword.__info__(:functions) == [from_struct: 1]
24+
assert Map.__info__(:functions) -- Keyword.__info__(:functions) == [
25+
from_struct: 1,
26+
intersect: 2,
27+
intersect: 3
28+
]
2529
end
2630

2731
test "get_and_update/3 raises on bad return value from the argument function" do

lib/elixir/test/elixir/map_test.exs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,29 @@ defmodule MapTest do
231231
end
232232
end
233233

234+
test "intersect/2" do
235+
map = %{a: 1, b: 2}
236+
237+
assert Map.intersect(map, %{a: 2}) == %{a: 2}
238+
assert Map.intersect(map, %{c: 3}) == %{}
239+
assert Map.intersect(%{a: 2}, map) == %{a: 1}
240+
assert Map.intersect(%{c: 3}, map) == %{}
241+
242+
assert Map.intersect(map, %{a: 2}) |> Map.intersect(%{a: 3, c: 3}) == %{a: 3}
243+
assert Map.intersect(map, %{c: 3}) |> Map.intersect(%{c: 4}) == %{}
244+
assert Map.intersect(map, %{a: 3, c: 3}) |> Map.intersect(%{a: 2}) == %{a: 2}
245+
end
246+
247+
test "intersect/3" do
248+
# When first map is bigger
249+
assert Map.intersect(%{a: 1, b: 2, c: 3}, %{c: 4, d: 5}, fn :c, 3, 4 -> :x end) ==
250+
%{c: :x}
251+
252+
# When second map is bigger
253+
assert Map.intersect(%{b: 2, c: 3}, %{a: 1, c: 4, d: 5}, fn :c, 3, 4 -> :x end) ==
254+
%{c: :x}
255+
end
256+
234257
test "implements (almost) all functions in Keyword" do
235258
assert Keyword.__info__(:functions) -- Map.__info__(:functions) == [
236259
delete: 3,

0 commit comments

Comments
 (0)