Reputation: 1328
I have two lists
1 = [%{name: "hi"}, %{name: "hu"}]
2 = [%{name: "hi"}, %{name: "ha"}]
Now I would like to have 2 lists that only contain the elements that are unique in each of the lists 1 and 2
1_uniq = [%{name: "hu"}]
2_uniq = [%{name: "ha"}]
How could I achieve this?
Upvotes: 0
Views: 1622
Reputation: 155
Using the same idea as @Dogbert, I prefer the following snippet because you do less iterations,
l1 = [%{name: "hi"}, %{name: "hu"}]
l2 = [%{name: "hi"}, %{name: "ha"}]
set = MapSet.new(l1 ++ l2)
l1_uniq = Enum.reject(set, &(Enum.member?(l2, &1)))
l2_uniq = Enum.reject(set, &(Enum.member?(l1, &1)))
You can achieve the same solution without using MapSet
:
l1 = [%{name: "hi"}, %{name: "hu"}]
l2 = [%{name: "hi"}, %{name: "ha"}]
set = Enum.uniq(l1 ++ l2)
l1_uniq = Enum.reject(set, &(Enum.member?(l2, &1)))
l2_uniq = Enum.reject(set, &(Enum.member?(l1, &1)))
Upvotes: 1
Reputation: 222118
You can create a list set of names for both the lists, intersect them to find common names, and then filter out all names that are common. Here's how you can do this with the MapSet
module in Elixir:
l1 = [%{name: "hi"}, %{name: "hu"}]
l2 = [%{name: "hi"}, %{name: "ha"}]
# set of names
s1 = for x <- l1, into: MapSet.new, do: x.name
s2 = for x <- l2, into: MapSet.new, do: x.name
# set of common names
common = MapSet.intersection(s1, s2)
# filter out any name that's in `common`
l1_unique = for x <- l1, !MapSet.member?(common, x.name), do: x
l2_unique = for x <- l2, !MapSet.member?(common, x.name), do: x
IO.inspect l1_unique
IO.inspect l2_unique
Output:
[%{name: "hu"}]
[%{name: "ha"}]
Upvotes: 2