Elixir中Zip映射SQL查询结果生成按年份分组的数据结构
Elixir SQL查询结果转结构化分组数据实现
方案1:匹配你原有思路的实现(先转关键字列表再分组)
你的Enum.zip思路完全可行,注意关键字列表的键需要是原子类型,所以先把字符串格式的列名转为原子即可:
# 1. 预处理列名:字符串转原子 columns = Enum.map(results.columns, &String.to_atom/1) # 2. 逐行将列名和数据配对,生成关键字列表格式的行数据 kw_rows = Enum.map(results.rows, fn row -> Enum.zip(columns, row) end) # 3. 按year字段分组 grouped_result = Enum.group_by(kw_rows, &Keyword.get(&1, :year))
执行后得到的grouped_result结构完全匹配预期:
%{ 2018 => [ [tour_id: 1, name: "asia", year: 2018, num_shows: 4, num_cities: 4, num_festivals: 3, num_countries: 3], [tour_id: 2, name: "north america", year: 2018, num_shows: 39, num_cities: 17, num_festivals: 2, num_countries: 2], [tour_id: 3, name: "europe", year: 2018, num_shows: 13, num_cities: 12, num_festivals: 9, num_countries: 10], [tour_id: 4, name: "las vegas shows", year: 2018, num_shows: 3, num_cities: 1, num_festivals: 0, num_countries: 1] ], 2022 => [ [tour_id: 5, name: "tour", year: 2022, num_shows: 13, num_cities: 10, num_festivals: 4, num_countries: 2] ] }
方案2:更高效的单遍历实现
不需要单独生成中间的全量关键字列表,可以直接在group_by阶段同时完成行格式转换和分组,减少一次全量数组遍历,数据量大时性能更好:
columns = Enum.map(results.columns, &String.to_atom/1) grouped_result = Enum.group_by( results.rows, # 分组键提取逻辑 fn row -> row |> Enum.zip(columns) |> Keyword.get(:year) end, # 分组后的值转换逻辑 fn row -> Enum.zip(columns, row) end )
注意事项
如果你的查询列名是动态生成、来自不可信的用户输入,不要使用String.to_atom/1(原子不会被垃圾回收,动态生成大量原子会导致内存泄漏),这种场景推荐用字符串键的Map替代关键字列表:
grouped_result = Enum.group_by( results.rows, fn row -> row |> Enum.zip(results.columns) |> Map.new() |> Map.get("year") end, fn row -> Map.new(Enum.zip(results.columns, row)) end )
内容的提问来源于stack exchange,提问作者I. Khan
相关产品推荐
相关产品推荐

