Elixir:更新地图列表中的特定值
Elixir: Update a specific value in a list of maps
给定以下地图列表:
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_x
和 velocity_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)
但这没有成功,可能是因为我的地图不使用原子键 - 到目前为止我看到的所有其他示例都使用原子键,或者添加新的键和值等。
还有什么我可以尝试的吗?
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}
被极度低估的 Access
in elixir 更强大,尤其是在深度更新方面。
尽管在这种特殊情况下,直截了当的 Map.put/3
似乎更容易,但我还是 post 使用 update_in/3
使用 Access
的解决方案。请注意,与 Map.put
.
不同,它可能用于修改 any 级别的深层嵌套结构
update_in(
ball_prop_list,
[Access.filter(&match?(%{"id" => "cue"}, &1))],
&Map.merge(&1, %{"velocity_x" => :new_velocity})
)
给定以下地图列表:
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_x
和 velocity_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)
但这没有成功,可能是因为我的地图不使用原子键 - 到目前为止我看到的所有其他示例都使用原子键,或者添加新的键和值等。
还有什么我可以尝试的吗?
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}
被极度低估的 Access
in elixir 更强大,尤其是在深度更新方面。
尽管在这种特殊情况下,直截了当的 Map.put/3
似乎更容易,但我还是 post 使用 update_in/3
使用 Access
的解决方案。请注意,与 Map.put
.
update_in(
ball_prop_list,
[Access.filter(&match?(%{"id" => "cue"}, &1))],
&Map.merge(&1, %{"velocity_x" => :new_velocity})
)