2010-02-16 6 views
1

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

[{:dim_location=>[{:dim_city=>:dim_state}]}, 
:dim_marital_status, 
{:dim_location=>[:dim_zip, :dim_business]}] 

в:

[{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]}, 
:dim_marital_status] 

Она должна поддерживать произвольный уровень глубины, хотя глубина редко будет выше 8 уровней.

+1

Что делает *» произвольный уровень глубины "* и *" 8 уровней глубокий "* означает? Примерный набор данных был бы хорош ... – DigitalRoss

+0

Целью этого является то, что я могу произвольно добавлять объединения в вызов поиска Rails ActiveRecord. Если я не нормализую массив/хэш, я отправлю его, он будет запрашивать одни и те же таблицы несколько раз. – rwl4

ответ

1

Пересмотренный после комментария:

source = [{:dim_location=>[{:dim_city=>:dim_state}]}, :dim_marital_status, {:dim_location=>[:dim_zip, :dim_business]}] 

expected = [{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]}, :dim_marital_status] 

source2 = [{:dim_location=>{:dim_city=>:dim_state}}, {:dim_location=>:dim_city}] 

def merge_dim_locations(array) 
    return array unless array.is_a?(Array) 
    values = array.dup 
    dim_locations = values.select {|x| x.is_a?(Hash) && x.has_key?(:dim_location)} 
    old_index = values.index(dim_locations[0]) unless dim_locations.empty? 
    merged = dim_locations.inject({}) do |memo, obj| 
    values.delete(obj) 
    x = merge_dim_locations(obj[:dim_location]) 
    if x.is_a?(Array) 
     memo[:dim_location] = (memo[:dim_location] || []) + x 
    else 
     memo[:dim_location] ||= [] 
     memo[:dim_location] << x 
    end 
    memo 
    end 
    unless merged.empty? 
    values.insert(old_index, merged) 
    end 
    values 
end 


puts "source1:" 
puts source.inspect 
puts "result1:" 
puts merge_dim_locations(source).inspect 
puts "expected1:" 
puts expected.inspect 

puts "\nsource2:" 
puts source2.inspect 
puts "result2:" 
puts merge_dim_locations(source2).inspect 
+0

Это ПОЛНОСТЬЮ работает отлично. Однако, когда я его подаю, он взрывается: [{: dim_location => {: dim_city =>: dim_state}}, {: dim_location =>: dim_city}] – rwl4

+0

OK Я немного изменил его, чтобы он не ударил вверх. Но каков результат, который должен был после обработки этого последнего элемента ввода? – dan

+0

Я создаю динамические запросы в Rails, которые связаны с разными объединениями, которые зависят от того, какие атрибуты мне нужны. У меня есть простой хеш, сопоставленный с атрибутами как ключ, и ассоциациями как значение. Если вам интересно, почему я сделал бы это так, это потому, что это довольно тяжелый объем данных, который хранится в схеме снежинки, и я создал named_scope, который позволяет мне запрашивать любое измерение, которое я хочу, на основе имени атрибута. – rwl4

0

Я не думаю, что там достаточно подробно в вашем вопросе, чтобы дать вам полный ответ, но это могло бы вы начали:

class Hash 
    def recursive_merge!(other) 
    other.keys.each do |k| 
     if self[k].is_a?(Array) && other[k].is_a?(Array) 
     self[k] += other[k] 
     elsif self[k].is_a?(Hash) && other[k].is_a?(Hash) 
     self[k].recursive_merge!(other[k]) 
     else 
     self[k] = other[k] 
     end 
    end 
    self 
    end 
end 
Смежные вопросы