假设我们有这样的地图:
state = %{
data: %{
"default" => %{
"someKeyword" => %{updated: 2}},
"baila" => %{
"someKeyword" => %{updated: 2}},
"morena" => %{updated: 2}
}
}
在这个例子中,只有2个“父键”要检查 - >实际应用中的default
和baila
会有100s +
现在,当我获得更新后的关键字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)
上面的例子很糟糕,不起作用,因为它似乎是一个混乱的解决方案,我在尴尬的长时间后放弃了:)
是否有更简单的方法来循环/检查上面的嵌套映射并在匹配时有条件地更新?
最终结果应为:
newKeyword = %{"someKeyword" => %{updated: 3, otherdata: 4}}
....
state = %{
data: %{
"default" => %{
"someKeyword" => %{updated: 3, otherdata: 4}},
"baila" => %{
"someKeyword" => %{updated: 3, otherdata: 4}},
"morena" => %{updated: 2}
}
}
答案 0 :(得分:3)
我发现了一种更好,更简单的方法,请参阅here。
my_map = %{
foo: %{
bar: %{
baz: "my value"
}
}
}
put_in(my_map, [:foo, :bar, :baz], "new value")
答案 1 :(得分:2)
以下是使用Enum.reduce/3
和Kernel.put_in/3
的一种方式:
state = %{
data: %{
"default" => %{
"someKeyword" => %{updated: 2}
},
"baila" => %{
"morena" => %{updated: 2}
}
}
}
new_keyword = %{"someKeyword" => %{updated: 3, otherdata: 4}}
[{new_key, new_value}] = Map.to_list(new_keyword)
new_state = Enum.reduce(Map.keys(state.data), state, fn key, state ->
old_value = state.data[key][new_key]
if old_value == nil || old_value && new_value.updated > old_value.updated do
put_in(state, [:data, key, new_key], new_value)
else
state
end
end)
IO.inspect new_state
输出:
%{data: %{"baila" => %{"morena" => %{updated: 2},
"someKeyword" => %{otherdata: 4, updated: 3}},
"default" => %{"someKeyword" => %{otherdata: 4, updated: 3}}}}
答案 2 :(得分:2)
虽然@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}}}}
以上内容适用于合并任何新数据地图。
感谢@Dogbert指出此处需要updated
的明确条件。