Ruby多层哈希补全:为分组统计结果填充缺失键的0值
补全多层哈希中缺失的键并设置默认值为0
开发Rails API做车辆查询与分组统计时,PostgreSQL的GROUP BY不会返回计数为0的分组结果,导致响应哈希中缺失对应键。现有实现仅支持两层哈希的缺失键填充,无法处理三层及更复杂的多层结构,需要实现能补全所有层级缺失键、并将值设为0的方法。
示例输入(三层哈希)
{ AUDI: { Deregistered: { Diesel: 56 }, Registered: { Petrol: 379, Diesel: 270, Electric: 447 } }, TESLA: { Registered: { Electric: 779 } } }
期望输出
{ AUDI: { Deregistered: { Petrol: 0, Diesel: 56, Electric: 0 }, Registered: { Petrol: 379, Diesel: 270, Electric: 447 } }, TESLA: { Deregistered: { Petrol: 0, Diesel: 0, Electric: 0 }, Registered: { Petrol: 0, Diesel: 0, Electric: 779 } } }
现有方法的问题
原代码的collect_keys会把所有层级的键混为一谈,fill_missing_keys用同一套键去填充所有层级,这不符合需求——不同层级的键集合是独立的(比如第一层是品牌,第二层是车辆状态,第三层是燃料类型),必须按层级分别处理。
解决方案
先构建每个层级的完整键集合,再递归遍历哈希,为每个层级补全缺失的键,同时为缺失的父键创建完整的子层级结构并填充默认值。
完整实现代码
# 构建每个层级的完整键集合,返回层级化的键哈希 def build_key_hierarchy(hash, hierarchy = {}) return hierarchy if hash.empty? current_level_keys = hash.keys.uniq hierarchy[:current] = current_level_keys # 收集所有子哈希,递归处理下一层级 child_hashes = hash.values.select { |v| v.is_a?(Hash) } unless child_hashes.empty? combined_child_hash = child_hashes.reduce({}, :merge) hierarchy[:children] = build_key_hierarchy(combined_child_hash) end hierarchy end # 递归填充缺失的键与层级结构 def fill_missing_hierarchy(hash, key_hierarchy, default_value = 0) # 补全当前层级的缺失键 key_hierarchy[:current].each do |key| unless hash.key?(key) # 如果有子层级,创建对应的空哈希并递归填充 hash[key] = if key_hierarchy[:children] fill_missing_hierarchy({}, key_hierarchy[:children], default_value) else default_value end else # 如果当前值是哈希且有子层级,递归处理子哈希 if hash[key].is_a?(Hash) && key_hierarchy[:children] fill_missing_hierarchy(hash[key], key_hierarchy[:children], default_value) end end end hash end # 对外暴露的入口方法 def complete_hash(hash, default_value = 0) key_hierarchy = build_key_hierarchy(hash) fill_missing_hierarchy(hash, key_hierarchy, default_value) end
代码说明
build_key_hierarchy:递归遍历输入哈希,收集每个层级的所有唯一键,生成层级化结构。比如示例输入会生成:{ current: [:AUDI, :TESLA], children: { current: [:Deregistered, :Registered], children: { current: [:Diesel, :Petrol, :Electric] } } }fill_missing_hierarchy:根据层级键结构递归补全缺失键——若键不存在,有子层级则创建空哈希并递归填充子结构,无则直接设默认值;若键已存在且值为哈希,继续递归处理子哈希。complete_hash:入口方法,调用前两个方法完成整个哈希的补全。
测试示例
input = { AUDI: { Deregistered: { Diesel: 56 }, Registered: { Petrol: 379, Diesel: 270, Electric: 447 } }, TESLA: { Registered: { Electric: 779 } } } puts complete_hash(input).inspect
运行后会得到期望的输出结果。
内容的提问来源于stack exchange,提问作者TobiasKnudsen
相关产品推荐
相关产品推荐

