如何反转地图?

时间:2017-05-30 20:43:05

标签: elixir

我有什么:

%{1 => #MapSet<[123, 234, 345, 456, 567]>,
  2 => #MapSet<[345, 456, 567, 678, 789]>}

我需要什么:

%{123 => #MapSet<[1],
  234 => #MapSet<[1],
  345 => #MapSet<[1,2],
  456 => #MapSet<[1,2],
  567 => #MapSet<[1,2],
  678 => #MapSet<[2],
  789 => #MapSet<[2]}

我似乎无法在长生不老药中找到这样的功能,而我写自己的尝试并不顺利。

编辑:

我最终将此作为我的最终解决方案:

Enum.reduce(x, %{}, fn {k, vs}, acc ->
   Enum.reduce(vs, acc, fn v, acc ->
     update_in(acc[v], fn
       nil -> MapSet.new([k])
       set -> set |> MapSet.put(k)
     end)
   end)
 end)

2 个答案:

答案 0 :(得分:2)

您可以在此处使用嵌套Enum.reduce/3

map = %{1 => MapSet.new([123, 234, 345, 456, 567]),
        2 => MapSet.new([345, 456, 567, 678, 789])}

Enum.reduce(map, %{}, fn {k, vs}, acc ->
  Enum.reduce(vs, acc, fn v, acc ->
    Map.update(acc, v, MapSet.new([k]), &MapSet.put(&1, k))
  end)
end)
|> IO.inspect

输出:

%{123 => #MapSet<[1]>, 234 => #MapSet<[1]>, 345 => #MapSet<[1, 2]>,
  456 => #MapSet<[1, 2]>, 567 => #MapSet<[1, 2]>, 678 => #MapSet<[2]>,
  789 => #MapSet<[2]>}

这可能会稍快一些,因为如果密钥已经存在,它不会创建MapSet:

Enum.reduce(map, %{}, fn {k, vs}, acc ->
  Enum.reduce(vs, acc, fn v, acc ->
    set = if set = Map.get(acc, v), do: MapSet.put(set, k), else: MapSet.new([k])
    Map.put(acc, v, set)
  end)
end)
|> IO.inspect

答案 1 :(得分:2)

我会发布@Dogbert稍微修改后的答案,该答案会使用更多惯用Map.get_and_update/3Kernel.SpecialForms.with/1

map = %{1 => MapSet.new([123, 234, 345, 456, 567]),
        2 => MapSet.new([345, 456, 567, 678, 789])}

Enum.reduce(map, %{}, fn {k, vs}, acc ->
  Enum.reduce(vs, acc, fn v, acc ->
    with {_, map} <- Map.get_and_update(acc, v, fn
      nil -> {nil, MapSet.new([k])}
      set -> {set, MapSet.put(set, k)}
    end), do: map
  end)
end)
|> IO.inspect