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

Elixir:迭代嵌套映射并在每个级别上插入键值对,elixir,Elixir,假设我有一个函数,它给我一个UUIDv4 def get_uuid() do # do magic end 我有一个嵌套映射,可以是n级深度: map = %{ name: "Alice", friends: [ %{ uid: "EXISTINGUID", name: "Betty" }, %{ name: "Bob", job: "Truck driver" } ] } 如何遍历整个映射,并在

假设我有一个函数,它给我一个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
键的条件,这将非常有用

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"
                }
              ]
            }
          }
        }
      }
    }
  ]
}
运行以下命令:

uuidconsistentyenforcer.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"
}

为了解释
元组
等,您需要在
模块
中相应地添加
run/1
函数。谢谢唯一一件事:使用Uuid作为模块名会从Elixir中产生一个错误。它不应该给您一个错误。我能够复制粘贴,就像在iex中一样。您看到的错误到底是什么,可能您已经在某处定义了一个名为Uuid的库。
[error]加载~/app/\u build/dev/lib/Uuid/ebin/Elixir.Uuid.beam失败::badfile[error]beam/beam\u load.c(1412):加载模块“Elixir.Uuid”时出错:目标代码中的模块名称为Elixir.Uuid
您是否可以将代码复制粘贴到此处,就像在新的
iex
中一样(例如,不要在现有项目中进行
iex-S混合
)?