Elixir: 重命名字典中的键

4

我有以下地图列表:

[
  %{
    code: "test",
    expired_at: ~U[2020-10-27 17:49:47Z],
  },
  %{
    code: "test",
    expired_at: ~U[2021-07-30 13:54:11Z],
  }
]

什么是将所有 map 实体列表中的关键字 "code" 重命名为 "product_code" 的最复杂方式?
2个回答

9

也许不是“最复杂的方法”,但我认为一种好的方式是使用模式匹配,并使用带有匹配要更改的条件的匿名函数,以及一个用于其他所有内容的匿名函数:

iex> l = [
...>   %{
...>     code: "test",
...>     expired_at: ~U[2020-10-27 17:49:47Z],
...>   },
...>   %{
...>     code: "test",
...>     expired_at: ~U[2021-07-30 13:54:11Z],
...>   }
...> ]
[
  %{code: "test", expired_at: ~U[2020-10-27 17:49:47Z]},
  %{code: "test", expired_at: ~U[2021-07-30 13:54:11Z]}
]
iex> Enum.map(l, &Map.new(&1, fn
...>   {:code, code} -> {:product_code, code}
...>   pair -> pair
...> end))
[
  %{expired_at: ~U[2020-10-27 17:49:47Z], product_code: "test"},
  %{expired_at: ~U[2021-07-30 13:54:11Z], product_code: "test"}
]

请注意使用Map.new/2,该函数使用给定函数应用于可枚举集合的元素来创建一个Map对象。
另一种更为清晰的替代方法是不使用像那样的Map.new/2或迭代地遍历Map对象的键,可以使用Map.delete/2Map.put/3
iex> Enum.map(l, fn %{code: code} = element ->
...>   element
...>   |> Map.delete(:code)
...>   |> Map.put(:product_code, code)
...> end)
[
  %{expired_at: ~U[2020-10-27 17:49:47Z], product_code: "test"},
  %{expired_at: ~U[2021-07-30 13:54:11Z], product_code: "test"}
]

6
虽然@sbacarob的答案完全正确,但如果要更新的主题是深度嵌套的话,可能会很快变得杂乱无章。
在这种情况下,提供了一个非常强大且被低估的机制来更新嵌套结构,称为Access。对于这个特定的情况,我们可以使用Kernel.update_in/3Access.all/0来获取列表中的所有元素。
update_in(
  list,
  [Access.all()],
  &(with {v, m} <- Map.pop(&1, :code),
    do: Map.put(m, :product_code, v))
)
#⇒ [
#    %{expired_at: ~U[2020-10-27 17:49:47Z], product_code: "test"},
#    %{expired_at: ~U[2021-07-30 13:54:11Z], product_code: "test"}
#  ]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接