Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby group_by in array of arrays

My array is

fruits = [["apple", "Tue"], ["mango", "Mon"], ["apple", "Wed"], ["orange", "Tue"]]

The result I want to get is to Group by Fruit and the count

[["apple", 2], ["mango", 1], ["orange", 1]]

I have always worked with just a single array when I wanted to group elements, how to work with array of arrays?

like image 648
gkolan Avatar asked Nov 21 '13 18:11

gkolan


4 Answers

fruits.group_by {|(fruit, day)| fruit }.map {|fruit, match| [fruit, match.count] }
like image 151
Stuart Nelson Avatar answered Oct 04 '22 05:10

Stuart Nelson


fruits = [["apple", "Tue"], ["mango", "Mon"], ["apple", "Wed"], ["orange", "Tue"]]
fruits.group_by(&:first).map{|k,v| [k,v.size]}
# => [["apple", 2], ["mango", 1], ["orange", 1]]
like image 24
Arup Rakshit Avatar answered Oct 04 '22 07:10

Arup Rakshit


Your example format looks a lot like a hash. If it's OK to have a hash, then you can do this.

count = Hash.new(0)
fruits.each { |f| count[f.first] += 1 }
# => {"apple"=>2, "mango"=>1, "orange"=>1} 

Then you can just convert it to an array.

count.to_a
# => [["apple", 2], ["mango", 1], ["orange", 1]] 

EDIT

As a side note, defining the hash as Hash.new(0) means that the default value is 0 instead of nil. This is how we get away with not defining any of the hash keys first.

EDIT 2

With Arup's suggestion this turns into

counts = fruits.each_with_object(Hash.new(0)) { |f, h| h[f.first] += 1 }

Depends on your preferences. I find the first a little easier to read.

like image 36
Dan Grahn Avatar answered Oct 04 '22 05:10

Dan Grahn


Being late to the party, I find the hors d'oeuvres nearly gone. Alas, I'm left with just a crumb:

f = fruits.map(&:first).sort
f.uniq.zip(f.chunk(&:dup).map(&:size)) # => [["apple", 2], ["mango", 2], ["orange", 2]]
  # => [["apple", 2], ["mango", 2], ["orange", 2]] 

Had I been more punctual, I would have grabbed one of those yummy group_by tarts.

like image 36
Cary Swoveland Avatar answered Oct 04 '22 07:10

Cary Swoveland