# Elixir generate inverted / reversed map

I would like to transform the input

elems = [a, b, c]
terms = [t1, t2]

@spec contains?(term, elem) :: boolean
def contains?(term, elem), do: #implementation


to either of

%{t1 => [a, b], t2 => [c]}


or

%{t1 => [a], t2 => [b, c]}


where

t1 |> contains?(a) #=> true
t1 |> contains?(b) #=> true
t1 |> contains?(c) #=> false

t2 |> contains?(a) #=> false
t2 |> contains?(b) #=> true
t2 |> contains?(c) #=> true


My current solution is as follows

defmodule Test do
def contains?(term, elem) do
elem in term
end

def test do
elems = [1,2,3]
terms = [[1,2], [2,3]]

elems
|> Enum.into(%{}, fn elem ->
{elem,
terms |> Enum.find(&contains?(&1, elem))}
end)
|> reverse_map()
end

defp reverse_map(map, reversed \\ %{})
defp reverse_map(map, reversed) when map_size(map) == 0, do: reversed

defp reverse_map(map, reversed) do
[key | _] = Map.keys(map)
{value, map} = Map.pop!(map, key)
reversed = Map.update(reversed, value, [key], &[key | &1])
reverse_map(map, reversed)
end
end


With this solution I'm generating the map

%{a => t1, b => t1, c => t2}


then reversing it and collecting collisions in a list.

But I feel this intermediate map is unnecessary and a solution could exist without it.

In addition I'm not sure my implementation of reverse_map is as elegant as it could be.

defmodule Test do
def contains?(term, elem) do
elem in term
end

def test do
elems = [1,2,3]
terms = [[1,2], [2,3]]

for e <- elems, reduce: %{} do
acc ->
key = Enum.find(terms, &contains?(&1, e))
Map.update(acc, key, [e], &[e|&1])
end
#=> %{[1, 2] => [2, 1], [2, 3] => }
end
end


Found a simple and elegant solution using a reduce comprehension.
Here, we iterate over each elem in elems, find the first term which contains it, then update our map with either term => [elem] or term => [elem|previous_elems] depending on if that key exists in the map yet.

Side note:
If I needed the elems in the same as order they were originally I could use & &1 ++ [e] instead of &[e|&1], but as I don't have that requirement it is more efficient to prepend the list.