中的嵌套映射查找键并更新其值



查找nested map中的键: sum并将其值更新为: bill * 100 + : coins

需要通过test1

test "test1" do
assert BcToInt.data(%{
count: 3,
sum: %{bills: 1, coins: 99},
tax: %{count: 3, sum: %{bills: 1, coins: 1}}
}) ==
%{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
end

我试图使用Map_replace()和使用is_map检查嵌套映射的值,如果true再次调用函数,但如何获得最终结果

def data(xmap) do
Enum.map(xmap, fn {_key, value} ->
keyy = :sum
aa = List.first(Map.values(xmap[keyy])) * 100 + List.last(Map.values(xmap[keyy]))
if Map.has_key?(xmap, keyy) do
Map.replace(xmap, keyy, aa)
if is_map(value) do
data1(value)
end
end
end)
end

下面是一个不使用外部库的版本:

def data(map) do
map =
case map[:sum] do
%{bills: bills, coins: coins} -> %{map | sum: bills * 100 + coins}
_ -> map
end
Map.new(map, fn
{k, v} when is_map(v) -> {k, data(v)}
entry -> entry
end)
end

用法:

iex(1)> data = ...
%{
count: 3,
sum: %{bills: 1, coins: 99},
tax: %{count: 3, sum: %{bills: 1, coins: 1}}
}
iex(2)> BcToInt.data(data)
%{count: 3, sum: 199, tax: %{count: 3, sum: 101}}

借助iteraptor库:

Mix.install([:iteraptor])
Iteraptor.map(data, fn
{_k, %{bills: bills, coins: coins}} -> bills * 100 + coins
# Is not `bill:` a typo?
{_k, %{bill: bills, coins: coins}} -> bills * 100 + coins
other -> other
end, yield: :all)
#⇒ %{count: 3, sum: 199, tax: %{count: 3, sum: 101}}

您的实现正确地使用递归来查看嵌套的数据结构。不过,它看起来像是在尝试使用Map.replace/3来尝试修改数据结构。Elixir只有不可变的数据结构,所以你需要从输入中构造一个新的映射,而不是试图就地更新它。

我可以在这里使用模式匹配实现递归:
def data(%{bills: bills, coins: coins}) do
bills * 100 + coins
end
def data(map) when is_map(map) do
Map.new(map, fn {k, v} -> {k, data(v)} end)
end
def data(any) do
any
end

在这样的设置下,如果data/1被调用时带有:bills:coins键的映射(不一定在名为:sum的字段中),它会将它们加在一起;在任何其他map上,它通过保留键的值递归;对于任何其他值,它返回原始值

def data(xmap) do
keyy = :sum
aa = List.first(Map.values(xmap[keyy])) * 100 + 
List.last(Map.values(xmap[keyy]))

Map.new(xmap, fn
{k, _v} when k == keyy -> {k, aa}
{k, v} when is_map(v) -> {k, data(v)}
{k, v} -> {k, v}
end)

end

最新更新