Ruby: вложенный ha sh теряет ключи и значения при слиянии с другим вложенным хешем - PullRequest
0 голосов
/ 08 мая 2020

У меня есть ha sh -

h1 = {"a"=>{"x"=>"1","y"=>"2"}, "b"=>"z"}

У меня есть другой ha sh h2, который в основном имеет обновленные значения для некоторых ключей в h1

h2 = {"a"=>{"x"=>"3"}, "b"=>"q"}

когда я делаю -

h1.merge(h2)

Я ожидаю, что он вернется-

{"a"=>{"x"=>"3","y"=>"2"}, "b"=>"q"}

Но на самом деле это дает мне- {"a"=>{"x"=>"3"}, "b"=>"q"}

Что мне нужно сделать, чтобы получить {"a"=>{"x"=>"3","y"=>"2"}, "b"=>"q"}?

Я не использую рельсы. Версия ruby - это 2.6.0

1 Ответ

3 голосов
/ 08 мая 2020

Принцип работы Hash#merge согласован: если ключ существует в обоих, то значение ключа объединенного ha sh заменяет первое во всех случаях. Вам понадобится рекурсивное слияние.

В Rails есть deep_merge . Но если вы не используете Rails или если он не соответствует вашим требованиям, вы можете довольно легко свернуть свой собственный.

Hash#merge поддерживает блок, который может помочь:

h1.merge(h2) { |k, old, new| (old.instance_of?(Hash) && new.instance_of?(Hash)) ?
                             old.merge(new) : new }

Это будет работать, если у вас есть только один слой встроенных хешей. Если у вас есть произвольная глубина вложенных хэшей, вы можете патч обезьяны Hash с deep_merge:

class Hash
  def deep_merge(h)
    self.merge(h) { |k, old, new| (old.instance_of?(Hash) && new.instance_of?(Hash)) ?
                            old.deep_merge(new) : new }
  end
end

Или что-то в этом роде ... :) Это будет рекурсивно объединяться, если есть ha sh в обоих случаях, в противном случае заменяет как обычно. Вы можете изменить его на свой вкус.

Примерка для вашего случая:

2.6.1 :008 > class Hash
2.6.1 :009?>   def deep_merge(h)
2.6.1 :010?>     self.merge(h) { |k, old, new| (old.instance_of?(Hash) && new.instance_of?(Hash)) ?
2.6.1 :011 >                                   old.deep_merge(new) : new }
2.6.1 :012?>   end
2.6.1 :013?> end
 => :deep_merge
2.6.1 :014 > h1 = {"a"=>{"x"=>"1","y"=>"2"}, "b"=>"z"}
 => {"a"=>{"x"=>"1", "y"=>"2"}, "b"=>"z"}
2.6.1 :015 > h2 = {"a"=>{"x"=>"3"}, "b"=>"q"}
 => {"a"=>{"x"=>"3"}, "b"=>"q"}
2.6.1 :016 > h1.deep_merge(h2)
 => {"a"=>{"x"=>"3", "y"=>"2"}, "b"=>"q"}
2.6.1 :017 >
...