2013-03-11 6 views
6

У меня есть массив объектов, отсортированный по нескольким свойствам этих объектов. В порядке приоритетности эти свойства: foo, bar и baz. Это означает, что объекты сначала сортируются по foo; то подпоследовательности, имеющие одинаковое значение foo, сортируются по bar; и затем те, которые имеют те же значения foo и bar, сортируются по baz.Создание вложенного хэша из отсортированного массива в Ruby-- recursive group_by

Я хотел бы превратить это в вложенный хеш, который отражает эту группировку. В основном я ищу рекурсивный Enumerable#group_by. Ключами будут значения foo, bar и baz; значения будут либо суб-хэшами, либо массивами объектов. Вот пример:

[obj1, obj2, ... objn].group_by_recursive(:foo, :bar, :baz) 
#=> { 
     foo_val_1 => { 
     bar_val_1 => { 
      baz_val_1 => [ 
      obj1, 
      obj2, 
      obj3 
      ], 
      baz_val_2 => [ 
      obj4, 
      obj5 
      ] 
     }, 
     bar_val_2 => { 
      baz_val_1 => [ 
      obj6, 
      obj7 
      ], 
      baz_val_2 => [ 
      obj8 
      ] 
     }, 
     }, 
     foo_val_2 => { 
     ... 
     }, 
     ... 
    } 

ответ

10

Пришло довольно неплохое решение. Обезьяна-патч Enumerable так:

module Enumerable 

    def group_by_recursive(*props) 
    groups = group_by(&props.first) 
    if props.count == 1 
     groups 
    else 
     groups.merge(groups) do |group, elements| 
     elements.group_by_recursive(*props.drop(1)) 
     end 
    end 
    end 

end 

Свойства вы передаете могут быть Procs или Symbols

+0

Мне нравится 'хэш. merge (hash) {...} 'трюк. –

+0

Сделал мой день, спасибо! – Daniel

1

Подобно Шона и недостающий обработки ошибок ...

class Array 
    def nested_group_by(*keys) 
    return self if keys.length == 0 
    groups = group_by(&keys.shift) 
    Hash[groups.map { | k, v | [k, v.nested_group_by(*keys)] }] 
    end 
end