Elixir 如何反转地图?

Elixir 如何反转地图?,elixir,Elixir,我所拥有的: %{1 => #MapSet<[123, 234, 345, 456, 567]>, 2 => #MapSet<[345, 456, 567, 678, 789]>} 您可以在此处使用嵌套的Enum.reduce/3: map = %{1 => MapSet.new([123, 234, 345, 456, 567]), 2 => MapSet.new([345, 456, 567, 678, 789])} E

我所拥有的:

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

您可以在此处使用嵌套的
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]>}

我将发布@Dogbert稍加修改的答案,该答案使用了更为惯用和:

map=%{1=>MapSet.new([1232343456567]),
2=>MapSet.new([34545675678789])
reduce(map,%{},fn{k,vs},acc->
枚举减少(vs,acc,fn v,acc->
使用{uuz,map}{nil,MapSet.new([k])}
set->{set,MapSet.put(set,k)}
结束),请执行以下操作:映射
(完)
(完)
|>检查

您能告诉我们到目前为止您已经尝试了什么吗?我有一些嵌套的reduce,但我不能完全让它工作。Dogbert的答案与我自己的答案非常接近。(我将第二个代码更改为更干净,几乎与第一个代码一样优雅。)如果出于某种原因,
Map.get(acc,v)
返回
false
,则
If set=
将调用
MapSet.new
并继续执行,导致运行时偶尔出现难以检测的故障。模式匹配总是比使用
if
IMHO更好。@mudasobwa为什么会返回
false
?这里只有一个
Map.put/3
调用,它只放入一个
MapSet
。True,但它会降低代码的结构化程度。是的,未来的读者可能会向自己保证只有一个
Map.put/3
,但我们为什么要强迫他们考虑这个问题并明确检查它呢?我不坚持任何方式都坚持
Kernel.SpecialForms.with/1
但是explicit
Kernel.SpecialForms.case/2
总是比
干净,如果
,则只需要
nil
作为唯一的错误值。如果映射可能会被
false
损坏,它也可能会“损坏”使用
nil
,在这种情况下,您的代码也将以类似的方式失败
Map.fetch如果您真的想保护映射不被获取无效值,那么会更好。是否有任何理由在这里使用
?模式
{{uu,map}
将始终与
map的返回值相匹配。get\u and\u update/3
@Dogbert,是和否。在这里,我将
一起使用视为一种防御编程。虽然在Elixir的未来版本中,
Map.get_和_update/3
的签名几乎不会改变,但我不想依赖算命,因此我更喜欢尽可能明确的控制流表达式。这里的
甚至比链式地图分配和地图返回看起来更好。当然,这是一个品味的问题,但我发现自己在任何可能的情况下都在使用
with
,只是为了减少可能的死角案例,而无需决定它是否可以返回任何其他内容。
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]>}
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
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