From: Robert Klemme Date: 2008-03-29T01:15:05+09:00 Subject: Re: numbers of a record in an array On 28.03.2008 03:41, Charles Calvert wrote: > On Tue, 25 Mar 2008 05:23:50 -0500, Robert Klemme wrote: > >> 2008/3/25, Jesús Gabriel y Galán : >>> On Tue, Mar 25, 2008 at 10:09 AM, Bu Mihai wrote: >>> > a have an array array=["a","b","c","a","b"] >>> > how can i find the numbers of "a", "b","c" items in the array? >>> >>> >>> Here's one way: >>> >>> irb(main):006:0> a = %w{a b a c b a c c} >>> => ["a", "b", "a", "c", "b", "a", "c", "c"] >>> irb(main):007:0> h = Hash.new {|h,k| h[k] = 0} >>> => {} >>> irb(main):008:0> a.each {|x| h[x] += 1} >>> => ["a", "b", "a", "c", "b", "a", "c", "c"] >>> irb(main):009:0> h >>> => {"a"=>3, "b"=>2, "c"=>3} >> Here's another > > Let's see if I understand this: > >> irb(main):001:0> a = %w{a b a c b a c c} >> => ["a", "b", "a", "c", "b", "a", "c", "c"] > > Creates an array of strings. > >> irb(main):002:0> a.inject(Hash.new(0)){|cnt,e| cnt[e]+=1; cnt} >> => {"a"=>3, "b"=>2, "c"=>3} > > Calls the method Enumerable::inject on the variable a, passing Hash.new(0) > as the initial value of memo, which is the accumulator. For each e in cnt > (which is a reference to the hash returned by "Hash.new"), it increments > the count whose key is the value of e. Probably just a spelling error: it should read "for each e in a ...". Your pseudo code has it actually correct. > I would pseudocode it as this: > > cnt = Hash.new(0) > foreach (e in a) > { > cnt[e] += 1 > } Btw, it's not far from pseudo code to Ruby code: irb(main):003:0> cnt = Hash.new 0 => {} irb(main):004:0> for e in a do irb(main):005:1* cnt[e] += 1 irb(main):006:1> end => ["a", "b", "a", "c", "b", "a", "c", "c"] irb(main):007:0> cnt => {"a"=>3, "b"=>2, "c"=>3} irb(main):008:0> :-) > What does the last "cnt" do, right before the closing brace, return a > reference to the hash? I tried removing that bit: > > a.inject(Hash.new(0)){|cnt,e| cnt[e]+=1} > > and got the error: > > TypeError: can't convert String into Integer > from (irb):2:in `[]' > from (irb):2 > from (irb):2:in `inject' > from (irb):2:in `each' > from (irb):2:in `inject' > from (irb):2 > from :0 > > I'm guessing that the use of "cnt" is controlling the interpretation of > the type returned by cnt[e], but I don't understand how. As Todd said, the return value of the block is the next iteration's accumulator: irb(main):009:0> (1..5).inject(0) {|*a| p a;a.first+10} [0, 1] [10, 2] [20, 3] [30, 4] [40, 5] => 50 This allows elegant code, as in irb(main):010:0> (1..5).inject(0){|s,x| s+x} => 15 which would not work if s was the same instance for every iteration. Kind regards robert