首页 > 解决方案 > 将相同的键数据合并到一个具有唯一键的映射中

问题描述

我有这个json

[
  %{
    "159.69.136.31" => [
      %{"2015" => ["4"]},
      %{"2016" => []},
      %{"2017" => ["9"]},
      %{"2018" => []},
      %{"2019" => ["05"]}
    ]
  },
  %{ 
    "94.130.139.38" => [
      %{"2015" => []},
      %{"2016" => []},
      %{"2017" => []},
      %{"2018" => ["5", "8"]},
      %{"2019" => []}
    ]
  },
  %{
    "94.130.217.56" => [
      %{"2015" => []},
      %{"2016" => []},
      %{"2017" => []},
      %{"2018" => []},
      %{"2019" => []}
    ]
  }
]

我想让它像

[
  %{"2015" => ["4"]},
  %{"2016" => []},
  %{"2017" => ["9"]},
  %{"2018" => ["5", "8"]},
  %{"2019" => ["05"]}
]

基本上,它合并了同一年的密钥和地图上可用的数据。我已经用不同的方法尝试过这个解决方案,但它没有用 Elixir: Merge list with same map keys to one map

更新:年份和 IP 是不变的 更新更多关于此的信息..

years = ["2015", "2016", "2017", "2018", "2019"]
servers = [@seaweedfs_new, @seaweedfs_old, @seaweedfs_oldest]

  Enum.map(servers, fn server ->
    type = seaweefs_type(server)
    attribute = seaweedfs_attribute(server)
    url = "http://" <> server <> ":8888" <> "/#{camera.exid}/snapshots/recordings/"
    year_values =
      Enum.map(years, fn year ->
        final_url = url <> year <> "/"
        %{
          "#{year}" => request_from_seaweedfs(final_url, type, attribute)
        }
      end)
    %{
      "#{server}" => year_values
    }
  end)

这就是我获取年份值并将它们设置为服务器对象的方式。如果有可能在获得年份值的同时将其分解?

"#{year}" => request_from_seaweedfs(final_url, type, attribute)这个请求基本上返回,例如"2015" => ["1", "2", "3"],在进入服务器之前是否有可能合并几年?

标签: elixir

解决方案


您需要获得地图的平面列表,然后合并所有地图。

input
|> Enum.flat_map(&Map.values/1)
|> Enum.flat_map(& &1)
|> Enum.reduce(&Map.merge(&1, &2, fn _, v1, v2 ->
  v1 ++ v2
end))
#⇒ %{
#    "2015" => ["4"],
#    "2016" => [],
#    "2017" => ["9"],
#    "2018" => ["5", "8"],
#    "2019" => ["05"]
# }

要获取地图列表(恕我直言,这是错误的设计决定),只需执行以下操作:

for {k, v} <- map, do: %{k => v}
#⇒ [
#    %{"2015" => ["4"]},
#    %{"2016" => []},
#    %{"2017" => ["9"]},
#    %{"2018" => ["5", "8"]},
#    %{"2019" => ["05"]}
# ]

推荐阅读