What's the best way to change a big array into multiple sub arrays based on the property of the objects in the original array? For example I have an array of objects(all objects have the same properties):
array = [
{:name => "Jim", :amount => "20"},
{:name => "Jim", :amount => "40"},
{:name => "Jim", :amount => "30"},
{:name => "Eddie", :amount => "7"},
{:name => "Eddie", :amount => "12"},
{:name => "Pony", :amount => "330"},
{:name => "Pony", :amount => "220"},
{:name => "Pony", :amount => "50"}
]
Note that all objects with the same name property are consecutive in the array. Now I want to group the objects into sub arrays based on the name property. What I need is:
result = [
[
{:name => "Jim", :amount => "20"},
{:name => "Jim", :amount => "40"},
{:name => "Jim", :amount => "30"}
],
[
{:name => "Eddie", :amount => "7"},
{:name => "Eddie", :amount => "12"}
],
[
{:name => "Pony", :amount => "330"},
{:name => "Pony", :amount => "220"},
{:name => "Pony", :amount => "50"}
]
]
What's the best way to do this? Thanks.
Use group_by for the heavy lifting and then map to pull out what you want:
result = array.group_by { |h| h[:name] }.map { |k, v| v }
For example:
>> results = array.group_by { |h| h[:name] }.map { |k, v| v }
>> pp results
[[{:name=>"Jim", :amount=>"20"},
{:name=>"Jim", :amount=>"40"},
{:name=>"Jim", :amount=>"30"}],
[{:name=>"Eddie", :amount=>"7"},
{:name=>"Eddie", :amount=>"12"}],
[{:name=>"Pony", :amount=>"330"},
{:name=>"Pony", :amount=>"220"},
{:name=>"Pony", :amount=>"50"}]]
You could also skip the map and go straight to Hash#values:
result = array.group_by { |h| h[:name] }.values
Thanks go to KandadaBoggu for pointing out this oversight.
If hashes with the same :name value are always consecutive elements you can do it like that:
result = array.each_with_object([]) do |e, memo|
if memo.last && memo.last.last[:name] == e[:name]
memo.last << e
else
memo << [e]
end
end
or you can use Enumerable#chunk (again, taking into account that elements with the same :name value are consecutive):
result = array.chunk{ |e| e[:name] }.map(&:last)
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