Слияние двух хешей с общим корнем - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть:

apartment1 = {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4}}}}
apartment2 = {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6}}}}

, которые разделяют {"base" => {"floor1" =>.

Как мне объединить квартиры под общей частью, чтобы получить:

{"base" => {"floor1" => {
  "apartment1" => {"rooms_number" => 6},
  "apartment2" => {"rooms_number" => 6}
}}}

Iслил apartment1 и apartment2 в apartments и получил это:

apartments = {}
apartments.merge!(apartment1)
# => {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4}}}} 
apartments.merge!(apartment2)
# => {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6}}}} 

Ответы [ 4 ]

0 голосов
/ 04 февраля 2019

Вы хотите объединиться не на корневом уровне, а на двух уровнях глубже.

apartment1.merge(apartment2){|_, h1, h2| h1.merge(h2){|_, h1, h2| h1.merge(h2)}}
# =>
# {"base" => {"floor1" => {
#   "apartment1" => {"rooms_number" => 4},
#   "apartment2" => {"rooms_number" => 6}
# }}}
0 голосов
/ 03 февраля 2019

Обработка вручную:

apartments = apartment1
apartments['base']['floor1'].merge!(apartment2['base']['floor1'])

p apartments
#=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}}

Или кража (!) Алгоритма глубокого слияния из Rails:

def deep_merge(first, second)
  first.merge(second) do |key, oldval, newval|
    oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
    newval = newval.to_hash if newval.respond_to?(:to_hash)
    oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? deep_merge(oldval, newval) : newval
  end
end

Так что вы можете использовать его в простом Ruby:

deep_merge(apartment1, apartment2) #=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}}
0 голосов
/ 04 февраля 2019

Следующий рекурсивный метод должен обеспечить желаемые результаты.

def combine_em(arr)
  (k1, k2), (v1, v2) = arr.map(&:flatten).transpose
  (k1==k2 && v1.is_a?(Hash)) ? { k1=>combine_em([v1, v2]) } :
    {}.merge(*arr) 
end

arr = [{"base"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
       {"base"=>{"floor1"=>{"apt2"=>{"room"=>6}}}}]
combine_em arr
  #=>  {"base"=>{"floor1"=>{"apt1"=>{"room"=>4},
  #                         "apt2"=>{"room"=>6}}}}

arr = [{"base"=>{"floor1"=>{"level1"=>{"apt1"=>{"room"=>4}}}}},
       {"base"=>{"floor1"=>{"level1"=>{"apt2"=>{"room"=>6}}}}}]
combine_em arr
  #=> {"base"=>{"floor1"=>{"level1"=>{"apt1"=>{"room"=>4},
  #                                   "apt2"=>{"room"=>6}}}}}

arr = [{"base"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
       {"base"=>{"floor2"=>{"apt1"=>{"room"=>6}}}}]
combine_em arr
  #=>  {"base"=>{"floor1"=>{"apt1"=>{"room"=>4}},
  #              "floor2"=>{"apt1"=>{"room"=>6}}}}

arr = [{"base"=>{"floor1"=>{"apt1"=>{"room1"=>4}}}},
       {"base"=>{"floor1"=>{"apt1"=>{"room2"=>6}}}}]
combine_em arr
  #=>  {"base"=>{"floor1"=>{"apt1"=>{"room1"=>4,
  #                                  "room2"=>6}}}}
arr = [{"base1"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
       {"base2"=>{"floor2"=>{"apt1"=>{"room"=>6}}}}]
combine_em arr
  #=> {"base1"=>{"floor1"=>{"apt1"=>{"room"=>4}}},
  #    "base2"=>{"floor2"=>{"apt1"=>{"room"=>6}}}}

arr = [{"base"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
       {"base"=>{"floor1"=>{"apt1"=>{"room"=>6}}}}]
combine_em arr
  #=>  {"base"=>{"floor1"=>{"apt1"=>{"room"=>6}}}}

Последний пример arr (если это могло произойти) может не дать желаемого результата.Если это так, то в этом случае необходимо будет указать требуемое возвращаемое значение.

Hash # merge был изменен в Ruby v2.6, чтобы разрешить несколько аргументов, поэтому мы можем теперьнапишите

arr = [{:a=>1}, {:b=>2}, {:c=>3}]
{}.merge(*arr)
  #=> {:a=>1, :b=>2, :c=>3}

Для поддержки более ранних версий Ruby напишите

arr.reduce(&:merge)

, что является сокращением для

arr.reduce { |h,g| h.merge(g) }

См. Enumerable # уменьшите (он же inject).

Чтобы получить полное представление о том, как работает рекурсия, может потребоваться засолить метод с помощью операторов puts.

0 голосов
/ 03 февраля 2019

Если вы используете Rails (или в любом случае, если вы хотите использовать ActiveSupport), вы можете сделать это через deep_merge:

2.5.1 :001 > apartment1= {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4} } }}
 => {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}}}} 
2.5.1 :002 > apartment2= {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6} } }}
 => {"base"=>{"floor1"=>{"apartment2"=>{"rooms_number"=>6}}}} 
2.5.1 :003 > apartments = apartment1.deep_merge apartment2
 => {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}} 

См. https://apidock.com/rails/Hash/deep_merge

Смотрите также этот похожий вопрос: Рубин: объединить вложенный хэш

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...