我有这个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"]
之类的信息,是否有可能在进入服务器之前先合并几年?
答案 0 :(得分:2)
您需要进入平面地图,然后将所有地图合并。
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"]}
# ]
答案 1 :(得分:1)
要回答您的第一个问题,即如何用X制作Y,这是一个快速解决方案:
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" => []}
]
}
]
代码:
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
返回:
[
{"2015", ["4"]},
{"2016", []},
{"2017", ["9"]},
{"2018", ["5", "8"]},
{"2019", ["05"]}
]
在管道和函数中插入更多IO.inspect
,以查看正在进行的转换。
答案 2 :(得分:0)
你为什么这样做:
"#{server}" => year_values
当您不在乎最终结果中的服务器名称时?这样做会使访问相关数据变得更加困难。
您可以结合使用for loop
选项(elixir 1.8+)和:reduce
(也称为列表理解)来创建结果图:
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
输出:
~/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"]
}
要获取列表,您可以执行以下操作:
My.get_data |> Enum.map(fn {key,val} -> %{key => val} end)
产生:
[
%{"2015" => ["3", "12", "9"]},
%{"2016" => ["5", "19", "15"]},
%{"2017" => ["14", "14", "19"]},
%{"2018" => ["4", "10", "11"]},
%{"2019" => ["12", "12", "7"]}
]
而且,如果需要维护数据的顺序,则可以执行以下操作:
My.get_data |> Enum.map(fn {key,val} -> %{key => Enum.reverse(val)} end)