我有一张看起来像的地图:
z = %{
"dd_1_a" => 1,
"dd_1_b" => 2,
"dd_1_c" => 3,
"dd_2_a" => 4,
"dd_2_b" => 5,
"dd_2_c" => 6
}
我正在尝试将其转换为以下形式的列表:
[
{a: 1, b: 2, c: 3},
{a: 4, b: 5, c: 6}
]
我已经了解到了
z
|> Map.new(fn {k, v} -> {tl(String.split(k, "_")), v} end )
|> Enum.group_by(fn {k, v} -> hd(k) end )
哪个给:
%{
"1" => [{["1", "a"], 1}, {["1", "b"], 2}, {["1", "c"], 3}],
"2" => [{["2", "a"], 4}, {["2", "b"], 5}, {["2", "c"], 6}]
}
我只是缺少下一步,那就是将值转换为关键字列表。
答案 0 :(得分:1)
在这里使用group_by
:
z
|> Enum.group_by(&String.at(elem(&1, 0), 3), &{String.to_atom(String.at(elem(&1, 0), 5)), elem(&1, 1)})
|> Map.values
|> Enum.map(&Map.new(&1))
答案 1 :(得分:0)
我假设1
中的dd_1_a
意味着它应该在dd_2_a
之前。在这种情况下,您需要在某些时候进行排序,因为不能保证枚举地图时的键顺序。
# ascending sort function
ascending = fn {k1, _}, {k2, _} -> k1 <= k2 end
%{
"dd_1_a" => 1,
"dd_1_c" => 3,
"dd_20_a" => 4,
"dd_1_b" => 2,
"dd_20_b" => 5,
"dd_20_c" => 6
}
# Parse the keys
|> Enum.map(fn {k, v} -> {Regex.run(~r/dd_(\d+)_(\w+)/, k), v} end)
# Convert into groups of 1 => [a: 1, b: 2, ...]
|> Enum.group_by(
fn {[_, k, _v1], _v2} -> String.to_integer(k) end,
fn {[_, _k, v1], v2} -> {String.to_atom(v1), v2} end
)
# Sort the keys, because the order of the keys in maps is not guaranteed
|> Enum.sort(ascending)
# Sort the internal lists too, because they were extracted from unsorted keys
|> Enum.map(fn {_, vals} -> Enum.sort(vals, ascending) end)
# Convert to tuples (skip this if you want keyword lists)
|> Enum.map(&List.to_tuple/1)
输出:
[{{:a, 1}, {:b, 2}, {:c, 3}}, {{:a, 4}, {:b, 5}, {:c, 6}}]
您提到您想要关键字列表,因此,如果跳过最后一步,输出为:
[[a: 1, b: 2, c: 3], [a: 4, b: 5, c: 6]]
答案 2 :(得分:0)
我回来了。 :-)
由于我在其他答案中提到的排序问题,我认为这不能解决问题,但确实可以回答您的问题:
%{
"1" => [{["1", "a"], 1}, {["1", "b"], 2}, {["1", "c"], 3}],
"2" => [{["2", "a"], 4}, {["2", "b"], 5}, {["2", "c"], 6}]
}
|> Enum.sort(fn {k1, _}, {k2, _} -> String.to_integer(k1) <= String.to_integer(k2) end)
|> Enum.map(fn {_, v} -> v end)
|> Enum.map(fn group -> Enum.map(group, fn {[_, k], v} -> {String.to_atom(k), v} end) end)
|> Enum.map(&List.to_tuple/1)
输出:
[{{:a, 1}, {:b, 2}, {:c, 3}}, {{:a, 4}, {:b, 5}, {:c, 6}}]
答案 3 :(得分:0)
您也可以尝试使用dd_ [index] _key来按索引顺序对元素进行排序
评论解释了一些代码
z = %{
"dd_1_a" => 1,
"dd_1_b" => 2,
"dd_1_c" => 3,
"dd_3_a" => 7, # indexes out of whack here
"dd_4_b" => 10, # indexes out of whack here
"dd_4_a" => 9, # indexes out of whack here
"dd_3_c" => 8, # indexes out of whack here
"dd_2_a" => 4,
"dd_2_b" => 5,
"dd_2_c" => 6
}
z
|> Enum.map(fn {"dd_" <> k1,v} -> # use pattern-matching to get the index and key
# can't use pattern-matching for this, because
# patterns need to have deterministic length
# so use String.split
[i, k] = String.split(k1, "_")
{i, k, v}
end) \
|> Enum.group_by(fn {i, _, _} -> i end) # group by the index
|> Enum.map(fn {i, arr} ->
# convert values of each index to an array
{i, arr |> Enum.map(fn {_i, k, v} -> {k |> String.to_atom, v} end)}
end)
|> Enum.sort(fn {i1, _}, {i2, _} -> i1 < i2 end) # sort by index
|> Enum.map(fn {_i, v} -> v |> List.to_tuple end) # remove the index, only keep key-values
output = [
{{:a, 1}, {:b, 2}, {:c, 3}},
{{:a, 4}, {:b, 5}, {:c, 6}},
{{:a, 7}, {:c, 8}},
{{:a, 9}, {:b, 10}}
]