4

I have an array of hashes

[ {:name => "bob", :type => "some", :product => "apples"},
  {:name => "ted", :type => "other", :product => "apples"},.... 
  {:name => "Will", :type => "none", :product => "oranges"} ]

and was wondering if there is a simple way to count the number of product's and store the count as well as the value in an array or hash.

I want the result to be something like:

@products =  [{"apples" => 2, "oranges => 1", ...}]
sawa
  • 165,429
  • 45
  • 277
  • 381
user2980830
  • 97
  • 2
  • 8

5 Answers5

9

You can do as

array = [
  {:name => "bob", :type => "some", :product => "apples"},
  {:name => "ted", :type => "other", :product => "apples"},
  {:name => "Will", :type => "none", :product => "oranges"} 
]

array.each_with_object(Hash.new(0)) { |h1, h2| h2[h1[:product]] += 1 }
# => {"apples"=>2, "oranges"=>1}
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
2

You can use Enumerable#group_by and Enumerable#map

array.group_by{|h| h[:product]}.map{|k,v| [k, v.size]}.to_h
# => {"apples"=>2, "oranges"=>1}
nrmb
  • 460
  • 1
  • 6
  • 17
Santhosh
  • 28,097
  • 9
  • 82
  • 87
2

While not exactly what the OP was looking for, this may be helpful to many. If you're just looking for the count of a specific product, you could do this:

array = [
  {:name => "bob", :type => "some", :product => "apples"},
  {:name => "ted", :type => "other", :product => "apples"},
  {:name => "Will", :type => "none", :product => "oranges"} 
]

array.count { |h| h[:product] == 'apples' }
# => 2
Alex Munoz
  • 21
  • 2
0

You could count:

hashes = [
  {:name => "bob", :type => "some", :product => "apples"},
  {:name => "ted", :type => "other", :product => "apples"},
  {:name => "Will", :type => "none", :product => "oranges"}
]

hashes.inject(Hash.new(0)) { |h,o| h[o[:product]] += 1; h }

Or maybe...

hashes.instance_eval { Hash[keys.map { |k| [k,count(k)] }] }

I do not know which is the more performant, the latter seims weird to read though.

ichigolas
  • 7,595
  • 27
  • 50
  • Can you try the code you have given in IRB? `hashes.inject(Hash.new(0)) { |h,(_,value)| h[value] += 1 }`.. It is completely wrong. – Arup Rakshit Jul 25 '14 at 03:44
  • I was trying to use inject as i have used it before to count items but have never seen this "(_,value)", thanks for your response – user2980830 Jul 25 '14 at 03:46
0

I would do:

items =[ {:name => "bob", :type => "some", :product => "apples"},
  {:name => "ted", :type => "other", :product => "apples"},
  {:name => "Will", :type => "none", :product => "oranges"} ]

 counts = items.group_by{|x|x[:product]}.map{|x,y|[x,y.count]}
 p counts #=> [["apples", 2], ["oranges", 1]]

Then if you need it as a Hash just do:

 Hash[counts]
hirolau
  • 13,451
  • 8
  • 35
  • 47