Robert Klemme
3/28/2008 4:10:00 PM
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 <jgabrielygalan@gmail.com>:
>>> On Tue, Mar 25, 2008 at 10:09 AM, Bu Mihai <mihai.bulhac@yahoo.com> 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