首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将相同的键值数据合并到一个具有唯一键值的映射中

将相同的键值数据合并到一个具有唯一键值的映射中
EN

Stack Overflow用户
提问于 2019-05-30 04:37:56
回答 2查看 443关注 0票数 0

我有这个json

代码语言:javascript
复制
[
  %{
    "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" => []}
    ]
  }
]

我想让它像这样

代码语言:javascript
复制
[
  %{"2015" => ["4"]},
  %{"2016" => []},
  %{"2017" => ["9"]},
  %{"2018" => ["5", "8"]},
  %{"2019" => ["05"]}
]

基本上,它合并了同年的关键字和地图上可用的数据。我已经用不同的方法尝试了这个解决方案,但它不起作用,Elixir: Merge list with same map keys to one map

更新:年份和IP是常量更新一点关于这个的更多信息..

代码语言:javascript
复制
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"],有没有可能在进入服务器之前合并一个头的年份?

EN

回答 2

Stack Overflow用户

发布于 2019-05-30 07:28:50

为了回答你的第一个问题,如何从X生成Y,这里有一个快速而粗糙的解决方案:

代码语言:javascript
复制
data = [
  %{
    "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" => []}
    ]
  }
]

代码:

代码语言:javascript
复制
data
|> Enum.map(&Map.values/1)
|> List.flatten
|> Enum.map(fn year_map -> year_map |> Map.to_list |> hd end)
|> Enum.reduce(%{}, fn {year, year_data}, acc ->
  Map.update(acc, year, year_data, &[&1 | year_data])
end)
|> Enum.map(fn {year, year_data} ->
  {year, List.flatten(year_data) |> Enum.reject(&is_nil/1)}
end)
|> IO.inspect

返回:

代码语言:javascript
复制
[
  {"2015", ["4"]},
  {"2016", []},
  {"2017", ["9"]},
  {"2018", ["5", "8"]},
  {"2019", ["05"]}
]

在流水线和函数中插入更多的IO.inspect,以查看正在进行哪些转换。

票数 1
EN

Stack Overflow用户

发布于 2019-05-30 11:00:06

你为什么要这样做:

代码语言:javascript
复制
"#{server}" => year_values

当您不关心最终结果中的服务器名称时?这样做会使访问相关数据变得更加困难。

您可以结合使用for loop (也称为列表理解)和:reduce选项(elixir 1.8+)来创建结果映射:

代码语言:javascript
复制
defmodule My do

  @years ["2015", "2016", "2017", "2018", "2019"]
  @servers ["new", "old", "oldest"] 

  def request_from_seaweedfs(url, _type, _attribute) do
    IO.puts url
    "#{:random.uniform(20)}"  #Returns a random string
  end

  def get_data do
    for server <- @servers, year <- @years, reduce: %{} do
      map -> #This is the map specified here --------^
        url = "http://#{server}:8888/camera.exid/snapshots/recordings/#{year}/"
        result = request_from_seaweedfs(url, "x", "y")
        IO.puts "#{year}: #{result}"
        Map.update(map, year, [result], &([result|&1]))
    end
  end

end

输出:

代码语言:javascript
复制
~/elixir_programs$ iex my.ex
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> My.get_data
http://new:8888/camera.exid/snapshots/recordings/2015/
2015: 9
http://new:8888/camera.exid/snapshots/recordings/2016/
2016: 15
http://new:8888/camera.exid/snapshots/recordings/2017/
2017: 19
http://new:8888/camera.exid/snapshots/recordings/2018/
2018: 11
http://new:8888/camera.exid/snapshots/recordings/2019/
2019: 7
http://old:8888/camera.exid/snapshots/recordings/2015/
2015: 12
http://old:8888/camera.exid/snapshots/recordings/2016/
2016: 19
http://old:8888/camera.exid/snapshots/recordings/2017/
2017: 14
http://old:8888/camera.exid/snapshots/recordings/2018/
2018: 10
http://old:8888/camera.exid/snapshots/recordings/2019/
2019: 12
http://oldest:8888/camera.exid/snapshots/recordings/2015/
2015: 3
http://oldest:8888/camera.exid/snapshots/recordings/2016/
2016: 5
http://oldest:8888/camera.exid/snapshots/recordings/2017/
2017: 14
http://oldest:8888/camera.exid/snapshots/recordings/2018/
2018: 4
http://oldest:8888/camera.exid/snapshots/recordings/2019/
2019: 12

%{
  "2015" => ["3", "12", "9"],
  "2016" => ["5", "19", "15"],
  "2017" => ["14", "14", "19"],
  "2018" => ["4", "10", "11"],
  "2019" => ["12", "12", "7"]
}

要获取列表,您可以执行以下操作:

代码语言:javascript
复制
My.get_data |> Enum.map(fn {key,val} -> %{key => val} end)

这会产生:

代码语言:javascript
复制
[
  %{"2015" => ["3", "12", "9"]},
  %{"2016" => ["5", "19", "15"]},
  %{"2017" => ["14", "14", "19"]},
  %{"2018" => ["4", "10", "11"]},
  %{"2019" => ["12", "12", "7"]}
]

而且,如果需要维护数据的顺序,您可以这样做:

代码语言:javascript
复制
My.get_data |> Enum.map(fn {key,val} -> %{key => Enum.reverse(val)} end)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56368167

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档