Updating a map’s values that are sets

Hey! Hope everyone is having a great day.

So, I have an empty map and I want to insert values inside of it. The thing is the keys of the map will be simple integers, however, the values will be sets or MapSet.

Now, I’ve tried doing these multiple ways using put_in or update_in as well as using the built-in functions of Maps. However, it either overwrites the existing value or adds nil to it. One such example of this is provided below:

values = [[1,2],[2,4],[5,4],[2,3],[1,7],[5,1],[1,2]]
map = values |> Enum.reduce(%{}, fn(v, map) -> put_in(map[Enum.at(v, 0)], MapSet.new([Enum.at(v, 1)])) end)
2 Likes

Are you looking for something like this?

iex> values
|> Enum.with_index()
|> Enum.map(fn {list, index} -> {index, MapSet.new(list)} end)
|> Map.new()

%{
  0 => #MapSet<[1, 2]>,
  1 => #MapSet<[2, 4]>,
  2 => #MapSet<[4, 5]>,
  3 => #MapSet<[2, 3]>,
  4 => #MapSet<[1, 7]>,
  5 => #MapSet<[1, 5]>,
  6 => #MapSet<[1, 2]>
}

Edit:

And then to update an entry:

iex> Map.update!(map, key, fn set -> MapSet.put(set, new_value) end)
1 Like

Based on your code, this is what I think you want.

iex(10)> values = [[1,2],[2,4],[5,4],[2,3],[1,7],[5,1],[1,2]]
iex(11)> map = 
...(11)> Enum.reduce(values, %{}, fn([k, v], map) ->
...(11)>   new_map_set = MapSet.new([v])
...(11)>   Map.update(map, k, new_map_set, fn existing_map_set ->
...(11)>     MapSet.union(existing_map_set, new_map_set)
...(11)>   end)
...(11)> end)
%{1 => #MapSet<[2, 7]>, 2 => #MapSet<[3, 4]>, 5 => #MapSet<[1, 4]>}

My advice is that always try to solve everything with the building blocks of Elixir. in this case Enum.reduce, Enum.reduce_while, Enum.map, list comprehensions, Enum.into, etc.
Once you master them, move onto more abstract stuff such as Kernel.get_and_update_in,

2 Likes