Elixir 使用多个键更新嵌套映射
假设我们有这样的地图:Elixir 使用多个键更新嵌套映射,elixir,Elixir,假设我们有这样的地图: state = %{ data: %{ "default" => %{ "someKeyword" => %{updated: 2}}, "baila" => %{ "someKeyword" => %{updated: 2}}, "morena" => %{updated: 2} } } 在本例
state = %{
data: %{
"default" => %{
"someKeyword" => %{updated: 2}},
"baila" => %{
"someKeyword" => %{updated: 2}},
"morena" => %{updated: 2}
}
}
在本例中,只需检查两个“父键”->default
和baila
,在实际应用程序中,将有100个+
现在,当我使用更新的关键字someKeyword
获取事件时,如何检查所有父关键字,并在找到关键字且新关键字的某些值高于旧关键字的值时有条件地更新
比如:
newKeyword = %{"someKeyword" => %{updated: 3, otherdata: 4}}
newKeywordkey = List.first(Map.keys(newKeyword))
keys = Map.keys(state.data)
Enum.each(keys, fn(x) ->
new_state = case Kernel.get_and_update_in(x, [newKeywordkey], fn(y) ->
if y.updated < newKeyword[newKeywordkey] do
....
end
{y, newKeyword}
end)
do
{l, b} -> b
end
end)
以下是使用和的一种方法:
输出:
%{data: %{"baila" => %{"morena" => %{updated: 2},
"someKeyword" => %{otherdata: 4, updated: 3}},
"default" => %{"someKeyword" => %{otherdata: 4, updated: 3}}}}
虽然@Dogbert的答案绝对正确(尽管它对一个键值对有效,但有一个限制),但有更简单的方法来实现目标
new_data = %{"someKeyword" => %{updated: 3, otherdata: 4}}
%{data: state.data
|> Enum.map(fn {k, v} ->
{k,
(if v["someKeyword"] == nil ||
v["someKeyword"][:updated] == nil ||
v["someKeyword"][:updated] < new_data[:updated],
do: v |> Map.merge(new_keyword), else: v)
}
end)
|> Enum.into(%{})}
#⇒ %{data: %{"baila" => %{"morena" => %{updated: 2},
# "someKeyword" => %{otherdata: 4, updated: 3}},
# "default" => %{"someKeyword" => %{otherdata: 4, updated: 3}}}}
new_data=%{“someKeyword”=>%{updated:3,otherdata:4}
%{data:state.data
|>枚举映射(fn{k,v}->
{k,
(如果v[“someKeyword”]==nil||
v[“someKeyword”][:updated]==nil||
v[“someKeyword”][:updated]<新数据[:updated],
do:v |>Map.merge(新的_关键字),else:v)
}
(完)
|>Enum.into(%{})
#⇒%%{数据:%%{“baila”=>%%{“morena”=>%{更新:2},
#“someKeyword”=>%{otherdata:4,更新:3},
#“默认值”=>%{“someKeyword”=>%{otherdata:4,更新:3}}
上述操作可用于合并任何新的数据映射
感谢@Dogbert指出这里需要更新的
的显式条件。我找到了一个非常简单的方法,请参阅
如果与someKeyword
关联的值对于所有子映射都是相同的,那么将其存储在不同的级别是否有意义呢?我认为这不会处理“如果找到了键并且新键的某些值高于旧键的值,则进行更新”,但是如果使用Map.merge/3
和简单的If
,我认为它的功能与我的代码相同,而且肯定会更干净。我一直使用这一个,因为它非常清晰简洁:)
%{data: %{"baila" => %{"morena" => %{updated: 2},
"someKeyword" => %{otherdata: 4, updated: 3}},
"default" => %{"someKeyword" => %{otherdata: 4, updated: 3}}}}
new_data = %{"someKeyword" => %{updated: 3, otherdata: 4}}
%{data: state.data
|> Enum.map(fn {k, v} ->
{k,
(if v["someKeyword"] == nil ||
v["someKeyword"][:updated] == nil ||
v["someKeyword"][:updated] < new_data[:updated],
do: v |> Map.merge(new_keyword), else: v)
}
end)
|> Enum.into(%{})}
#⇒ %{data: %{"baila" => %{"morena" => %{updated: 2},
# "someKeyword" => %{otherdata: 4, updated: 3}},
# "default" => %{"someKeyword" => %{otherdata: 4, updated: 3}}}}
my_map = %{
foo: %{
bar: %{
baz: "my value"
}
}
}
put_in(my_map, [:foo, :bar, :baz], "new value")