Sean Mackesey Sean Mackesey -4 years ago 67
Ruby Question

Creating a nested hash from a sorted array in Ruby-- recursive group_by

I have an array of objects that has been sorted according to several properties of these objects. In order of priority, these properties are

foo
,
bar
and
baz
. This means that the objects are first sorted by
foo
; then subsequences having the same
foo
value are sorted by
bar
; and then those with the same
foo
and
bar
values are sorted by
baz
.

I would like to turn this into a nested hash that reflects this grouping. Basically I'm looking for a recursive
Enumerable#group_by
. The keys would be values of
foo
,
bar
, and
baz
; the values would be either sub-hashes or arrays of the objects. Here is an example:

[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 => {
...
},
...
}

Answer Source

Came up with a pretty good solution. Monkey-patch Enumerable like this:

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

The properties you pass can be either Procs or Symbols

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download