Mike Manfrin
Mike Manfrin

Reputation: 2762

Flatten, sort, and map an array of objects in to an array of hashes (with a few collapsed values)

Situation:

I have an array of objects. Each object has a name, and ID, and another attribute. I want to map this in to an array of hashes that have the name, an array of ids, and the other attribute (same per name).

So I have something like:

[{:name=>"Hello", :id=>1}, {:name=>"Hello", :id=>2}, {:name=>"Bye", :id=>3}]

I want it to look like

[{:name=>"Bye", :ids=>[3]}, {:name=>"Hello", :ids=>[1, 2]}]

I have tried using chunk, but I'm unable to properly figure out how to use it without it being a massive pile of poorly-cooked spaghetti.

Right now I have managed to cleanly sort (at the beginning), and I can map it fine, but I feel like further iterating over it is needlessly wasteful, and I should group or chunk them beforehand.

Without the chunking, my code looks like this:

list_of_designers.sort!{ |x,y| I18n.transliterate(x.name).upcase <=> I18n.transliterate(y.name).upcase }

list_of_designers.map do |designer|
  {
    name: designer.name,
    designer_ids: [designer.id]
  }
end

However, this leaves me with siblings (i.e., designers with the same name, but different IDs). How can I cleanly collapse these siblings?

Upvotes: 2

Views: 912

Answers (2)

Jon
Jon

Reputation: 10898

Try this:

original = [{:name=>"Hello", :id=>1}, {:name=>"Hello", :id=>2}, {:name=>"Bye", :id=>3}]
modified = original.map { |i| i[:name] }.uniq.map { |name| {name: name, ids: ary.find_all { |i| i[:name] == name }.map { |i| i[:id] } } }
# => [{:name=>"Hello", :ids=>[1, 2]}, {:name=>"Bye", :ids=>[3]}]

Upvotes: 0

Arup Rakshit
Arup Rakshit

Reputation: 118289

I would do as below :

a = [{:name=>"Hello", :id=>1}, {:name=>"Hello", :id=>2}, {:name=>"Bye", :id=>3}]
a.group_by{|h| h[:name] }.map{|k,v| {:name => k, :ids => v.map{|h| h[:id]}}}
# => [{:name=>"Hello", :ids=>[1, 2]}, {:name=>"Bye", :ids=>[3]}]

Upvotes: 2

Related Questions