2016-06-24 3 views
0

Я пытаюсь создать задачу грабли, которая получает данные от модели и генерирует файл локали, такой как en.yml.Как значения группы по ключам глубоких хэшей?

Например, входные данные:

[ 
    {a: {w: 0}, b: '2', c: '3'}, 
    {a: {q: 1}}, 
    {aa: {bb: {cc: '4'}}}, 
    {aa: {bb: {ee: '4'}}} 
] 

Выходные данные должны выглядеть так:

{ 
     a: {w: 0, q: 1}, 
     b: '2', 
     c: '3', 
     aa: {bb: {cc: '4', ee: '4'} }} 
    } 

So значения одних и тех же клавиш на том же глубоком уровне должны быть сгруппированы .. Как я могу сделать это с помощью массива ruby ​​и хэш-методов?

+2

Что произойдет, если есть конфликт (тот же ключ на одном уровне имеет 2 разных значения)? Например, у вас есть {aa: {bb: {cc: '4'}}}, {aa: {bb: {cc: '12'}}} – Pholochtairze

ответ

1

Rails Активное расширение поддержки ядра, Hash#deep_merge выполняет то же самое. Вы могли бы использовать этот камень вместо того, чтобы изобретать колесо.

require "active_support/core_ext/hash" 
arr = [ 
    {a: {w: 0}, b: '2', c: '3'}, 
    {a: {q: 1}}, 
    {aa: {bb: {cc: '4'}}}, 
    {aa: {bb: {ee: '4'}}} 
] 

p arr.reduce {|h1, h2| h1.deep_merge(h2)} 
#=> {:a=>{:w=>0, :q=>1}, :b=>"2", :c=>"3", :aa=>{:bb=>{:cc=>"4", :ee=>"4"}}} 

Если вы не»хотите использовать драгоценный камень, вы можете скопировать код deep_merge из Rails code base here.

1

Вы можете использовать рекурсивный метод для наложенной структуры хэша.

require 'yaml' 

def group_by_keys(sub_hash, export) 
    sub_hash.each do |k, v| 
    if Hash === v 
     export[k] ||= {} 
     self.send(__method__, v, export[k]) 
    else 
     export[k] = v 
    end 
    end 
end 

yaml = "[ 
    {a: {w: 0}, b: '2', c: '3'}, 
    {a: {q: 1}}, 
    {aa: {bb: {cc: '4'}}}, 
    {aa: {bb: {ee: '4'}}} 
]" 

imput = YAML.load(yaml) 

export = imput.each_with_object({}){|sub_hash, exp| group_by_keys(sub_hash, exp)} 

экспорт

p export 

# { 
# "a" => {"w" => 0, "q" => 1}, 
# "b" => "2", 
# "c" => "3", 
# "aa" => { 
#  "bb" => {"cc" => "4", "ee" => "4"} 
# } 
# } 

Я надеюсь, что это помогает

+0

Молодцы. Я раньше не видел 'send (__ method__, ...)'. Это просто, чтобы позволить вам изменить имя метода, не задумываясь об изменении его в теле метода? (Я полагаю, вы знаете, что вам не нужно «я».) –

+0

@CarySwoveland Спасибо;) И вы правы. –

0
# No gems needed, to scale however you'll need to add code 
hash_array = [{a: {w: 0}, b: "2", c: "3"}, {a: {q: 1}}, {aa: {bb: {cc:"4"}}}, {aa: {bb: {ee: "4" }}}] 

new_hash = {} 
test_array = [] 
hash_array.each do |hashes| 
    if test_array.include?(hashes.keys[0]) 
    if hashes.values[0].values[0].class == Hash 
     merge_this = hashes.values[0].values[0] 
     new_hash[hashes.keys[0]].values[0].merge!(merge_this) 
    else 
     new_hash[hashes.keys[0]].merge!(hashes.values[0]) 
    end 
    else 
    new_hash.merge!(hashes) 
    end 
    test_array << hashes.keys[0] 
end 
# You can easily move braces into standard .yml format 
p new_hash # returns {:a=>{:w=>0, :q=>1}, :b=>"2", :c=>"3", :aa=>{:bb=>{:cc=>"4", :ee=>"4"}}} 
Смежные вопросы