【问题标题】:Elixir: Update a specific value in a list of mapsElixir:更新地图列表中的特定值
【发布时间】:2021-03-23 20:55:00
【问题描述】:

鉴于以下地图列表:

ball_prop_list = 
[
  %{"id" => "cue", "is_idle" => true, "velocity_x" => 0.0, "velocity_z" => 0.0, "x" => -15.0, "z" => 0.0},
  %{"id" => "ball_1", "is_idle" => true, "velocity_x" => 0.0, "velocity_z" => 0.0, "x" => 15.0, "z" => 0.0},
  %{"id" => "ball_2", "is_idle" => true, "velocity_x" => 0.0, "velocity_z" => 0.0, "x" => 17.0, "z" => 1.1},
  %{"id" => "ball_3", "is_idle" => true, "velocity_x" => 0.0, "velocity_z" => 0.0, "x" => 17.0, "z" => -1.1}
]

我该如何改变,比如说,只更改"id" => "cue"velocity_xvelocity_y,并保持其他所有内容不变?

我只是尝试使用更新的值创建一个新列表(这不一定是我的目标),例如:

new_prop_list = Enum.map(balls_json_list, fn(val) -> 
  if val["id"] == "cue" do
    Map.put(val, "velocity_x" velocity_vector[:x])
    Map.put(val, "velocity_z" velocity_vector[:z])
  end
end)

但这没有成功,可能是因为我的地图不使用原子键 - 到目前为止我看到的所有其他示例都使用原子键,或者添加新的键和值等。

还有什么我可以尝试的吗?

【问题讨论】:

  • 如果这是您要经常做的事情,您可能需要考虑将您的列表转换为地图,这样您就可以通过 id 查找并避免每次都迭代列表。
  • @AdamMillerchip 我会记住这一点,谢谢!现在我只是按照程序其余部分要求的格式。

标签: elixir


【解决方案1】:

中有被严重低估的Access,它更强大,尤其是在深度更新方面。

尽管在这种特殊情况下,简单的 Map.put/3 可能看起来更容易,但我还是会使用 Access 发布带有 update_in/3 的解决方案。请注意,它可能用于修改 any 级别的深层嵌套结构,这与 Map.put 不同。

update_in(
  ball_prop_list,
  [Access.filter(&match?(%{"id" => "cue"}, &1))],
  &Map.merge(&1, %{"velocity_x" => :new_velocity})
)

【讨论】:

  • 非常感谢。我一定会查看Access 模块。
【解决方案2】:

Map.put/3 不会就地修改地图(因为 Elixir 中没有数据结构可以修改),而是创建一个新地图。

另外,您错过了 2 个逗号。

new_ball_prop_list = Enum.map(ball_prop_list, fn
  %{"id" => "cue"} = map ->
    map
    |> Map.put("velocity_x", velocity[:x])
    |> Map.put("velocity_y", velocity[:y])
  other_map ->
    other_map
end)

你也可以试试Map.merge/2%{map | k1 => v1, k2 => v2}

【讨论】:

  • 如果我要在更新这些值之前进行操作或某种计算,我会把它放在哪里,上面的代码?
  • @zack_falcon 在第一个->下,也就是匿名函数的第一个子句里面。顺便说一句,从技术上讲,在任何子句中放置任意数量的表达式都是完全有效的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-24
相关资源
最近更新 更多