如何简化计算PostgreSQL两字段值的频率差?
问题描述
我有一个包含a、b两列的PostgreSQL数据库表,查询全表得到以下结果:
{1, 2}, {2, 3}, {2, 3}
各值在列中的出现次数统计如下:
- 1在a列出现1次,b列出现0次
- 2在a列出现2次,b列出现1次
- 3在a列出现0次,b列出现2次
我需要得到这样的输出:
{1, 1}, {2, 1}, {3, -2}
其中第一个元素是数据库中的值,第二个元素是a列出现次数减去b列出现次数的差值。
我已经用下面的Elixir代码实现了需求,但想找更简洁的写法:
f0 = query_result |> Enum.frequencies_by(&elem(&1, 0)) f1 = query_result |> Enum.frequencies_by(&elem(&1, 1)) (f0 |> Map.keys) ++ (f1 |> Map.keys) |> Enum.uniq |> Enum.into(%{}, fn key -> {key, (f0[key] || 0) - (f1[key] || 0)} end)
优化实现方案
可以用Enum.reduce一次性遍历结果集,直接维护统计差值的映射表,仅需遍历一次数据,代码更简洁高效:
query_result |> Enum.reduce(%{}, fn {a, b}, acc -> acc |> Map.update(a, 1, &(&1 + 1)) |> Map.update(b, -1, &(&1 - 1)) end) |> Enum.map(fn {k, v} -> {k, v} end) # 如需转为列表格式,保留此步骤
代码说明
- 遍历每一行
{a, b}:对a列的值,在映射表中对应计数加1(对应a列出现次数+1);对b列的值,对应计数减1(等价于抵消b列出现次数,即差值-1) - 最终得到的映射表直接存储每个值对应的
a列次数 - b列次数差值 - 如果需要和目标输出一致的列表结构,加上
Enum.map转换即可,默认返回的Map也可直接使用
内容的提问来源于stack exchange,提问作者Alsaraha
相关产品推荐
相关产品推荐

