Рекурсивная функция в ruby ​​перезаписывает вложенные атрибуты клонированной (object.dup) переменной - PullRequest
0 голосов
/ 11 мая 2018

У меня есть такой хэш:

entity = {1=> nil, 2 => {3 => nil, 4 => 1}}

Я написал функцию, которая может удалять нулевые значения данного объекта с помощью рекурсии.

def clear_null_values(entity)
   entity.each do |key, value|
     if value == nil || value.blank?
       entity.delete(key)
     elsif value.is_a? Hash
       clear_null_values(value)
       entity.delete(key) if value.blank?
     end
   end
end 

А также мне нужна оригинальная сущность для других целей. Поэтому я продублировал хеш-переменную, а затем очистил нулевые значения.

final_entity = entity.dup
clear_null_values(entity)
puts entity
puts final_entity

Результат:

{2 => {4 => 1}}
{1=> nil, 2 => {4 => 1}} # the nested values are overwritten.

В идеале final_entity должен совпадать с исходной сущностью.

Вопрос1: Почему entity.dup копирует только внешний хеш?

Вопрос2: Как сделать final_entity точной копией оригинальной сущности, т.е. даже если мы изменим сущность, то также не изменится final_entity?

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

На мой взгляд, было бы чище вычислять хэш, очищенный от значений nil, работая непосредственно с entities, а не с его копией.

def clear_null_values(entity)
  entity.each_with_object({}) do |(k,v),h|
    next if v.nil?
    h[k] = Hash === v ? clear_null_values(v) : v
  end
end

entities = { 1=>nil, 2=>{ 3=>nil, 4=>1 } }

clear_null_values entities
  #=> {2=>{4=>1}}

Мы можем подтвердить, что entities не был мутирован.

entities
  #=> {1=>nil, 2=>{3=>nil, 4=>1}}
0 голосов
/ 11 мая 2018

Попробуйте вместо этого использовать deep_dup, только ваш исходный код dup - с крайним хэшем.

final_entity = entity.deep_dup
clear_null_values(entity)
puts entity
puts final_entity

Выходы:

{2=>{4=>1}}
{1=>nil, 2=>{3=>nil, 4=>1}}

Примечание: Rails также добавляет Hash#compact, который можно использовать для упрощения clear_null_values.

...