Home > OS >  in a nested map find key and update its value
in a nested map find key and update its value

Time:01-13

find key : sum in nested map and update its value to : bill * 100 : coins

Need to pass 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

I tried to do it using Map_replace() and checking value for nested map using is_map and call function again if true but how to get end result

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

CodePudding user response:

Here's a version without using external libraries:

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

Usage:

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}}

CodePudding user response:

With a help of iteraptor library:

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}}

CodePudding user response:

Your implementation correctly uses recursion to look into nested data structures. It looks like it's trying to use Map.replace/3 to try to modify the data structure in place, though. Elixir only has immutable data structures, so you need to construct a new map from the input rather than trying to update it in place.

I might implement the recursion here using pattern matching:

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

With this setup, if data/1 is called with a map with the :bills and :coins keys (not necessarily in a field named :sum) it adds them together; on any other map, it recurses through the values preserving the keys; and on any other value it returns the original value as-is.

CodePudding user response:

 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
  • Related