在 Elixir 的嵌套地图中交换键

Swap keys in nested map in Elixir

我在 Elixir 中有以下结构的嵌套映射:

%{
  key1: %{
    nkey1: val1,
    nkey2: val4
  },
  key2: %{
    nkey1: val2,
    nkey2: val5
  },
  key3: %{
    nkey1: val3,
    nkey2: val6
  }
}

我想将其转换为以下结构。

%{
  nkey1: %{
    key1: val1,
    key2: val2,
    key3: val3
  },
  nkey2: %{
    key1: val4,
    key2: val5,
    key3: val6
}

保证所有顶级键都包含同一组嵌套键。

有什么好的、简单的方法可以完成这种转换,我能够以某种方式实现它,但它并没有给我留下真正的印象漂亮

坦率地说,我怀疑是否有超级优雅的解决方案。我会使用嵌套 Enum.reduce/3.

map = %{
  key1: %{nkey1: 1, nkey2: 4},
  key2: %{nkey1: 2, nkey2: 5},
  key3: %{nkey1: 3, nkey2: 6}
}

Enum.reduce(map, %{}, fn {k, v}, acc ->
  Enum.reduce(v, acc, fn {kk, vv}, acc ->
    Map.update(acc, kk, %{k => vv}, &Map.put(&1, k, vv))
  end)
end)
#⇒ %{nkey1: %{key1: 1, key2: 2, key3: 3},
#    nkey2: %{key1: 4, key2: 5, key3: 6}}

与阿列克谢的回答类似,我是这样做的:

map
|> Enum.reduce(%{}, fn {key, val}, acc ->
  Map.merge(acc, val |> Enum.reduce(%{}, fn {nkey, nval}, nacc ->
    Map.put(nacc, nkey, Map.new([{key, nval}]))
  end),
  fn _dkey, dval1, dval2 -> Map.merge(dval1, dval2) end)
end)

我认为 Aleksei 的回答更优雅,可能更有效。

我自己喜欢遍历嵌套数据的理解。

for {key, nested} <- input, {nkey, value} <- nested, reduce: %{} do
  acc ->
    put_in(acc, [Access.key(nkey, %{}), key], value)
    # The Access functions are less-known, so you may prefer this for understandability:
    # Map.update(acc, nkey, %{key => value}, &Map.put(&1, key, value))
end