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