Ruby多层Hash遍历赋值时同键数据被覆盖问题如何解决
问题原因
Hash被覆盖的核心问题出在这行代码:
calendario_hash['calendario_status'][ano][mes][dia][hora]['audiencias'] = []
你每次遍历audiencia记录时,无论对应小时下的audiencias数组是否已经存在,都会强制重置为空数组,之前追加的记录自然就被覆盖了,只会保留最后一条遍历的记录。
修改方案
只需要把这行数组初始化的逻辑改成「数组不存在时才初始化」即可,同时还可以优化冗余的数据库查询逻辑(你开头已经取过pendente状态,不需要再重复查库),完整修改后代码如下:
audiencias = Documento::Audiencia.obter_audiencias_por_periodo(orgao_id, data_inicial, data_final) audiencias.each do |audiencia| ano = audiencia.dth_audiencia.year mes = audiencia.dth_audiencia.month - 1 dia = audiencia.dth_audiencia.day hora = audiencia.dth_audiencia.hour situacao = audiencia.pendente? # 逐层初始化Hash,避免undefined method `[]=' for nil:NilClass错误 calendario_hash['calendario_status'] ||= {} calendario_hash['calendario_status'][ano] ||= {} calendario_hash['calendario_status'][ano][mes] ||= {} calendario_hash['calendario_status'][ano][mes][dia] ||= {"pendente" => situacao} calendario_hash['calendario_status'][ano][mes][dia][hora] ||= {} # 只有audiencias数组不存在时才初始化,不要每次都重置 calendario_hash['calendario_status'][ano][mes][dia][hora]['audiencias'] ||= [] audiencia_serializado = JSON.parse(audiencia.to_json( :only => [:id, :desc_audiencia, :dth_audiencia, :finalizada, :nr_processo_judicial], :include => { :objeto_tramitacao => {:only => [:id, :nr_objeto_tramitacao, :referencia]}, :audiencia_tipo => {:only => [:id, :nm_audiencia_tipo]} } )) # 直接用之前已经拿到的situacao,不需要重复查库 audiencia_serializado['audiencia']['pendente'] = situacao calendario_hash['calendario_status'][ano][mes][dia][hora]['audiencias'] << audiencia_serializado['audiencia'] end
可选优化(简化Hash初始化逻辑)
如果希望省略逐层判断nil的冗余代码,可以给calendario_hash设置默认Proc,自动生成嵌套Hash:
# 提前设置Hash的默认结构,不需要每次遍历都判断nil calendario_hash['calendario_status'] ||= Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = Hash.new { |h3, k3| h3[k3] = Hash.new { |h4, k4| h4[k4] = {} } } } } audiencias.each do |audiencia| ano = audiencia.dth_audiencia.year mes = audiencia.dth_audiencia.month - 1 dia = audiencia.dth_audiencia.day hora = audiencia.dth_audiencia.hour situacao = audiencia.pendente? calendario_hash['calendario_status'][ano][mes][dia]["pendente"] ||= situacao calendario_hash['calendario_status'][ano][mes][dia][hora]['audiencias'] ||= [] # 后续序列化、追加记录的逻辑不变 end
内容的提问来源于stack exchange,提问作者Tilipim
相关产品推荐
相关产品推荐

