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 => {
...
},
...
}
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
Similar to Sean's and lacking error handling ...
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With