axelson

axelson

Scenic Core Team

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

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

manukall

this doesn’t do what you would think, though:

iex(4)> match?(a, %{x: 5})
true
peerreynders

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

NobbZ

Do not pin here:

iex(1)> a = %{a: 1}
iex(2)> b = %{a: 1, b: 2}
iex(3)> match?(a, b)
true
kelvinst

kelvinst

Now I see my code is actually the same as @peerreynders second suggestion but in only one line.

If you want also, his last suggestion can be written as:

map1 = %{a: 1}
map2 = %{a: 1, b: 2}

map1
|> Map.to_list()
|> Enum.all?(&(&1 in map2))

But I still think MapSet.subset?/2 is clearer, and as you can see in its code, looks like it does pretty much the same thing.

kelvinst

kelvinst

Now that @axelson has a workaround for it, I want to bring a little discussion: shouldn’t his example work? I mean this one:

map1 = %{a: 1}
map2 = %{a: 1, b: 2}

^map1 = map2

I totally expected it to work. Didn’t you?​

I mean, if we think logically: if %{a: 1} = b works and
a = %{a: 1}, then ^a = b should work.

Do any of you know why it doesn’t? Is there a specific reason for it?

Where Next?

Popular in Questions Top

Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement