chokchit
How can I compare two list of maps?
Hey guys, just want a little help.
(1) How can I compare two list of maps and always supersedes list_2 over list_1 if they have the same name? and (2) return the map of list_1 if it doesn’t have a similar name?
Given:
list_1 = [%{id: 1, name: "John"}, %{id: 1, name: "Jane"}, %{school_id: 1, name: "Ryan"}, ...]
list_2 = [%{id: 2, name: "John"}, %{id: 2, name: "Jane"}, ...]
Expected result:
[
%{school_id: 2, name: "John"},
%{school_id: 2, name: "Jane"},
%{school_id: 1, name: "Ryan"},
...
]
Most Liked
imatmati
Enum.concat(list_2,list_1)
|> Enum.sort( &(&1.name<= &2.name))
|> Enum.dedup_by(&(&1.name))
6
amnu3387
Two other ways are using Enum.reduce/3 or a reduction function:
Enum.concat(Test.list_2(), Test.list_1())
|> Enum.reduce({[], %{}}, fn
(%{name: name}, {_, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches) ->
full_acc
(%{name: name} = el, {acc, map_matches}) ->
{[el | acc], Map.put(map_matches, name, true)}
end)
|> elem(0)
Or
def build(list, acc \\ {[], %{}})
def build([], {acc, _}), do: acc
def build([%{name: name} | t], {_acc, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches), do: build(t, full_acc)
def build([%{name: name} = el | t], {acc, map_matches}) do
build(t, {[el | acc], Map.put(map_matches, name, true)})
end
#test.exs
defmodule Test do
@list_1 Enum.reduce_while(Stream.cycle([0]), {0, []},
fn(_n, {count, acc}) when count < 25000 ->
{:cont, {count + 1, [%{id: count + 1, name: "a_#{count}_name"} | acc]}}
(_, {_, acc}) -> {:halt, acc}
end)
@list_2 @list_1 |> List.delete_at(10) |> List.delete_at(50) |> List.delete_at(100) |> List.delete_at(500) |> List.delete_at(750)
def list_1, do: @list_1
def list_2, do: @list_2
# reduce w/ function
def build(list, acc \\ {[], %{}})
def build([], {acc, _}), do: acc
def build([%{name: name} | t], {_acc, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches), do: build(t, full_acc)
def build([%{name: name} = el | t], {acc, map_matches}) do
build(t, {[el | acc], Map.put(map_matches, name, true)})
end
def test do
test1 =
Enum.concat(Test.list_2(), Test.list_1())
|> Enum.reduce({[], %{}}, fn
(%{name: name}, {_, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches) -> full_acc
(%{name: name} = el, {acc, map_matches}) ->
{[el | acc], Map.put(map_matches, name, true)}
end)
|> elem(0)
|> Enum.sort()
test2 =
:lists.flatten([Test.list_2() | Test.list_1()])
|> Enum.reduce({[], %{}}, fn
(%{name: name}, {_, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches)-> full_acc
(%{name: name} = el, {acc, map_matches}) ->
{[el | acc], Map.put(map_matches, name, true)}
end)
|> elem(0)
|> Enum.sort()
test3 =
Map.new(Test.list_1(), &{&1.name, &1})
|> Map.merge(Map.new(Test.list_2(), &{&1.name, &1}))
|> Enum.map(&elem(&1, 1))
|> Enum.sort()
test4 =
Enum.concat(Test.list_2(), Test.list_1())
|> Enum.sort( &(&1.name<= &2.name))
|> Enum.dedup_by(&(&1.name))
|> Enum.sort()
test5 =
Enum.map(Test.list_1(), fn %{name: n} = m ->
Enum.find(Test.list_2(), m, &match?(%{name: ^n}, &1))
end)
|> Enum.sort()
test6 =
Enum.concat(Test.list_2(), Test.list_1())
|> Test.build()
|> Enum.sort()
IO.inspect(test1 == test2, label: "1 == 2")
IO.inspect(test1 == test3, label: "1 == 3")
IO.inspect(test1 == test4, label: "1 == 4")
IO.inspect(test1 == test5, label: "1 == 5")
IO.inspect(test1 == test6, label: "1 == 6")
end
end
defmodule TestTest do
Test.test()
end
Benchee.run(
%{
"Enum.reduce & concat" => fn ->
Enum.concat(Test.list_2(), Test.list_1())
|> Enum.reduce({[], %{}}, fn
(%{name: name}, {_, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches) -> full_acc
(%{name: name} = el, {acc, map_matches}) ->
{[el | acc], Map.put(map_matches, name, true)}
end)
|> elem(0)
end,
"Enum.reduce & flatten" => fn ->
:lists.flatten([Test.list_2() | Test.list_1()])
|> Enum.reduce({[], %{}}, fn
(%{name: name}, {_, map_matches} = full_acc) when :erlang.is_map_key(name, map_matches)-> full_acc
(%{name: name} = el, {acc, map_matches}) ->
{[el | acc], Map.put(map_matches, name, true)}
end)
|> elem(0)
end,
"reduce function" => fn ->
Enum.concat(Test.list_2(), Test.list_1())
|> Test.build()
end,
"map_merge" => fn ->
Map.new(Test.list_1(), &{&1.name, &1})
|> Map.merge(Map.new(Test.list_2(), &{&1.name, &1}))
|> Enum.map(&elem(&1, 1))
end,
"sort_dedup" => fn ->
Enum.concat(Test.list_2(), Test.list_1())
|> Enum.sort( &(&1.name<= &2.name))
|> Enum.dedup_by(&(&1.name))
end,
"enum_find" => fn ->
Enum.map(Test.list_1(), fn %{name: n} = m ->
Enum.find(Test.list_2(), m, &match?(%{name: ^n}, &1))
end)
end
},
time: 2
)
Which gives:
1 == 2: true
1 == 3: true
1 == 4: true
1 == 5: true
1 == 6: true
Operating System: macOS"
CPU Information: Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz
Number of Available Cores: 8
Available memory: 8 GB
Elixir 1.7.2
Erlang 21.0
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 2 s
memory time: 0 μs
parallel: 1
inputs: none specified
Estimated total run time: 24 s
Benchmarking Enum.reduce & concat...
Benchmarking Enum.reduce & flatten...
Benchmarking enum_find...
Benchmarking map_merge...
Benchmarking reduce function...
Benchmarking sort_dedup...
Name ips average deviation median 99th %
reduce function 53.90 18.55 ms ±9.14% 19.02 ms 23.64 ms
Enum.reduce & flatten 51.34 19.48 ms ±9.26% 19.40 ms 23.77 ms
Enum.reduce & concat 50.97 19.62 ms ±8.30% 20.04 ms 22.77 ms
map_merge 46.92 21.31 ms ±7.83% 21.44 ms 25.13 ms
sort_dedup 43.35 23.07 ms ±6.16% 23.07 ms 26.70 ms
enum_find 0.0740 13515.56 ms ±0.00% 13515.56 ms 13515.56 ms
Comparison:
reduce function 53.90
Enum.reduce & flatten 51.34 - 1.05x slower
Enum.reduce & concat 50.97 - 1.06x slower
map_merge 46.92 - 1.15x slower
sort_dedup 43.35 - 1.24x slower
enum_find 0.0740 - 728.52x slower
The results change depending on the length of the lists, but the function is always a tad faster
4
gregvaughn
Enum.map(list_1, fn %{name: n} = m ->
Enum.find(list_2, m, &match?(%{name: ^n}, &1))
end)
2
peerreynders
iex(1)> list_1 = [%{id: 1, name: "John"}, %{id: 1, name: "Jane"}, %{id: 1, name: "Ryan"}]
[%{id: 1, name: "John"}, %{id: 1, name: "Jane"}, %{id: 1, name: "Ryan"}]
iex(2)> list_2 = [%{id: 2, name: "John"}, %{id: 2, name: "Jane"}]
[%{id: 2, name: "John"}, %{id: 2, name: "Jane"}]
iex(3)> map_2 = Map.new(list_2, fn %{name: name} = item -> {name, item} end)
%{"Jane" => %{id: 2, name: "Jane"}, "John" => %{id: 2, name: "John"}}
iex(4)> result =
...(4)> Enum.map(list_1, fn %{name: name} = item ->
...(4)> case Map.fetch(map_2, name) do
...(4)> {:ok, new_item} ->
...(4)> new_item
...(4)> _ ->
...(4)> item
...(4)> end
...(4)> end)
[%{id: 2, name: "John"}, %{id: 2, name: "Jane"}, %{id: 1, name: "Ryan"}]
iex(5)>
2
OvermindDL1
Another way:
iex(1)> list_1 = [%{id: 1, name: "John"}, %{id: 1, name: "Jane"}, %{school_id: 1, name: "Ryan"}]
[%{id: 1, name: "John"}, %{id: 1, name: "Jane"}, %{name: "Ryan", school_id: 1}]
iex(2)> list_2 = [%{id: 2, name: "John"}, %{id: 2, name: "Jane"}]
[%{id: 2, name: "John"}, %{id: 2, name: "Jane"}]
iex(3)>
nil
iex(4)> Map.merge(Map.new(list_1, &{&1.name, &1}), Map.new(list_2, &{&1.name, &1})) |> Enum.map(&elem(&1, 1))
[%{id: 2, name: "Jane"}, %{id: 2, name: "John"}, %{name: "Ryan", school_id: 1}]
I.E.:
Map.new(list_1, &{&1.name, &1})
|> Map.merge(Map.new(list_2, &{&1.name, &1}))
|> Enum.map(&elem(&1, 1))
2
Popular in Questions
Hello, I get Persian date from my client and convert it to normal calendar like this:
def jalali_string_to_miladi_english_number(persi...
New
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
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it.
I’m very interested in Elixir,...
New
Hello!
Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this:
...
New
i’m a new one to elixir
which editor can i use
vs code? or atom?
Thanks! :smiley:
New
Hello,
I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these
buyer = %{
id: ...
New
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this
"1000"
What is the ...
New
Hey,
I have a NanoPi-M3 and try to install Elixir on their Ubuntu image. I followed the Raspberry Pi installation instructions from the ...
New
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
Other popular topics
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this:
...
New
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
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
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine)
This is a plugin that adds support for Elixir to JetBrains IntelliJ...
New
I have an umbrella app.
Some of the apps inside depend on other apps in the umbrella, unsurprisingly.
I'm writing a test for one of t...
New
Hi,
I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Hello everybody,
usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: )
Hello all, this is ...
New
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New







