Elixir:迭代嵌套映射并在每个级别上插入键值对

时间:2018-03-14 22:57:21

标签: elixir

假设我有一个函数可以给我一个UUIDv4。

def get_uuid() do
  # do magic
end

我有一个嵌套的地图,可以是n级深度:

map = %{
  name: "Alice",
  friends: [
    %{
      uid: "EXISTINGUID",
      name: "Betty"
    },
    %{
      name: "Bob",
      job: "Truck driver"
    }
  ]
}

如何遍历完整的地图并在每个级别确保有一个键uid,如果没有,请插入get_uuid()的调用值?

预期结果:

map = %{
  name: "Alice",
  uid: "NEWUUID",
  friends: [
    %{
      uid: "EXISTINGUUID",
      name: "Betty"
    },
    %{
      uid: "ANOTHERNEWUUID"
      name: "Bob",
      job: "Truck driver"
    }
  ]
}

如果没有条件查找现有的uid密钥,那将非常有用。

1 个答案:

答案 0 :(得分:1)

defmodule Uuid do
  def generate(), do: :some_uuid
end

defmodule UuidConsistencyEnforcer do 
  @uuid_key :uid
  def run(some_list) when is_list(some_list), do: Enum.map(some_list, &run/1)

  def run(some_map) when is_map(some_map) do
    some_map
    |> Map.update(@uuid_key, Uuid.generate(), fn existing_uuid -> existing_uuid end)
    |> Enum.reduce(%{}, fn 
      {key, a_map = %{}}, a -> Map.merge(a, %{key => run(a_map)})
      {key, not_a_map}, a -> Map.merge(a, %{key => run(not_a_map)})
    end)
  end

  def run(some_value), do: some_value
end

测试:

给出一个深度嵌套的地图,例如:

map = %{
  name: "Alice",
  uid: "NEWUUID",
  friends: [
    %{
      uid: "EXISTINGUUID",
      name: "Betty"
    },
    %{
      name: "Bob",
      job: "Truck driver"
    },
    %{
      n1: %{
        n2: %{
          n3: %{
            n4: %{
              name: "Alice",
              uid: "NEWUUID",
              friends: [
                %{
                  uid: "EXISTINGUUID",
                  name: "Betty"
                },
                %{
                  name: "Bob",
                  job: "Truck driver"
                }
              ]
            }
          }
        }
      }
    }
  ]
}

运行以下内容:

UuidConsistencyEnforcer.run(map)

将呈现:

%{
  friends: [
    %{name: "Betty", uid: "EXISTINGUUID"},
    %{job: "Truck driver", name: "Bob", uid: :some_uuid},
    %{
      n1: %{
        n2: %{
          n3: %{
            n4: %{
              friends: [
                %{name: "Betty", uid: "EXISTINGUUID"},
                %{job: "Truck driver", name: "Bob", uid: :some_uuid}
              ],
              name: "Alice",
              uid: "NEWUUID"
            },
            uid: :some_uuid
          },
          uid: :some_uuid
        },
        uid: :some_uuid
      },
      uid: :some_uuid
    }
  ],
  name: "Alice",
  uid: "NEWUUID"
}