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.