axelson
How can you assert that a map in a variable matches another map that is a superset?
Given these two maps:
map1 = %{a: 1}
map2 = %{a:1, b: 2}
This works fine:
%{a: 1} = map2
But these do not:
iex> ^map1 = map2
** (MatchError) no match of right hand side value: %{a: 1, b: 2}
iex> match?(^map1, map2)
false
Assuming I have a subset of what I want to match in a variable is there a way to use pattern matching to check that I have a subset?
Marked As Solved
peerreynders
The trivial/pedestrian (i.e. no pattern match) way:
map1 = %{a: 1}
map2 = %{a: 1, b: 2}
set1 = MapSet.new(map1)
set2 = MapSet.new(map2)
IO.puts("map1 ⊆ map2 #{MapSet.subset?(set1, set2)}")
IO.puts("map2 ⊆ map1 #{MapSet.subset?(set2, set1)}
$ elixir demo.exs
map1 ⊆ map2 true
map2 ⊆ map1 false
$
or
map1 = %{a: 1}
map2 = %{a: 1, b: 2}
map3 = %{c: 3}
subset? =
fn (map1, map2) ->
keys = Map.keys(map1)
map2
|> Map.take(keys)
|> Map.equal?(map1)
end
IO.puts("map1 ⊆ map2 #{subset?.(map1, map2)}")
IO.puts("map2 ⊆ map1 #{subset?.(map2, map1)}")
IO.puts("map3 ⊆ map2 #{subset?.(map3, map2)}")
$ elixir demo2.exs
map1 ⊆ map2 true
map2 ⊆ map1 false
map3 ⊆ map2 false
and another
map1 = %{a: 1}
map2 = %{a: 1, b: 2}
map3 = %{c: 3}
subset? =
fn (map1, map2) ->
in_other =
fn {key, value} ->
{:ok, value} == Map.fetch(map2, key)
end
map1
|> Map.to_list()
|> Enum.all?(in_other)
end
IO.puts("map1 ⊆ map2 #{subset?.(map1, map2)}")
IO.puts("map2 ⊆ map1 #{subset?.(map2, map1)}")
IO.puts("map3 ⊆ map2 #{subset?.(map3, map2)}")
$ elixir demo3.exs
map1 ⊆ map2 true
map2 ⊆ map1 false
map3 ⊆ map2 false
$
I have the sneaking suspicion that the pattern is a compile time construct - it’s the binding that happens at runtime.
Also Liked
manukall
this doesn’t do what you would think, though:
iex(4)> match?(a, %{x: 5})
true
peerreynders
My gut pick is this one:
subset? =
fn (map1, map2) ->
in_other =
fn {key, value} ->
{:ok, value} == Map.fetch(map2, key)
end
map1
|> Map.to_list()
|> Enum.all?(in_other)
end
as it simply verifies that all the necessary key/value pairs are present and will stop as soon as that is not the case.
In this case I also prefer to use fetch/2 in order the leverage the underlying map functionality rather than relying on in/2’s macro magic even if it makes the code a bit more verbose (so be it).
One thing to be aware of is that the empty set is a subset of any other set - the same is true for empty maps.
NobbZ
Do not pin here:
iex(1)> a = %{a: 1}
iex(2)> b = %{a: 1, b: 2}
iex(3)> match?(a, b)
true
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









