numbers of a record in an array

B

Bu Mihai

a have an array array=["a","b","c","a","b"]
how can i find the numbers of "a", "b","c" items in the array?
 
J

Jesús Gabriel y Galán

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}

Hope this helps,

Jesus.
 
R

Robert Klemme

2008/3/25 said:
a have an array array=3D["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 =3D %w{a b a c b a c c}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):007:0> h =3D Hash.new {|h,k| h[k] =3D 0}
=3D> {}
irb(main):008:0> a.each {|x| h[x] +=3D 1}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):009:0> h
=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Here's another

irb(main):001:0> a =3D %w{a b a c b a c c}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):002:0> a.inject(Hash.new(0)){|cnt,e| cnt[e]+=3D1; cnt}
=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Jes=FAs, note that you do not need the block form of Hash.new because of
the way + works. It is sufficient to make 0 the default element.

Kind regards

robert

--=20
use.inject do |as, often| as.you_can - without end
 
J

Jesús Gabriel y Galán

2008/3/25 said:
a have an array array=3D["a","b","c","a","b"]
how can i find the numbers of "a", "b","c" items in the array?
irb(main):006:0> a =3D %w{a b a c b a c c}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):007:0> h =3D Hash.new {|h,k| h[k] =3D 0}
=3D> {}
irb(main):008:0> a.each {|x| h[x] +=3D 1}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):009:0> h
=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Here's another

irb(main):001:0> a =3D %w{a b a c b a c c}

=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):002:0> a.inject(Hash.new(0)){|cnt,e| cnt[e]+=3D1; cnt}

=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Jes=FAs, note that you do not need the block form of Hash.new because of
the way + works. It is sufficient to make 0 the default element.

Oh, that's right. I'm so used to that form for defaulting to an array :).
You say the reason is because of how + works, but is it not the reason
the fact that 0 is an immediate value
of which there's only one instance? So having the same reference to
the 0 object works, whereas having the same
reference to an array (for example) wouldn't achieve the desired effect?

Thanks,

Jesus.
 
R

Robert Klemme

2008/3/25 said:
2008/3/25 said:
a have an array array=3D["a","b","c","a","b"]
how can i find the numbers of "a", "b","c" items in the array?
irb(main):006:0> a =3D %w{a b a c b a c c}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):007:0> h =3D Hash.new {|h,k| h[k] =3D 0}
=3D> {}
irb(main):008:0> a.each {|x| h[x] +=3D 1}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):009:0> h
=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Here's another

irb(main):001:0> a =3D %w{a b a c b a c c}

=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):002:0> a.inject(Hash.new(0)){|cnt,e| cnt[e]+=3D1; cnt}

=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Jes=FAs, note that you do not need the block form of Hash.new because= of
the way + works. It is sufficient to make 0 the default element.


Oh, that's right. I'm so used to that form for defaulting to an array :)=
 
J

Jesús Gabriel y Galán

No, this has nothing to do with immediate values. The reason why this
works is that an operation is used that creates a new instance
(Fixnum#+ in this case) and uses assignment to place a new value on
every iteration. This also works with arrays and other non immediate
and even mutable instances:

irb(main):001:0> collector =3D Hash.new []
=3D> {}
irb(main):002:0> 10.times {|i| collector[i%3] +=3D }
=3D> 10


Ah, ok, now I see what you mean. I didn't consider this case, because
you are creating intermediate arrays every iteration. In my head I was
equating the +=3D for Fixnums with << for Arrays in this idiom, if you see
what I mean.

Thanks,

Jesus.
 
R

Robert Klemme

2008/3/25 said:

No, this has nothing to do with immediate values. The reason why this
works is that an operation is used that creates a new instance
(Fixnum#+ in this case) and uses assignment to place a new value on
every iteration. This also works with arrays and other non immediate
and even mutable instances:

irb(main):001:0> collector =3D Hash.new []
=3D> {}
irb(main):002:0> 10.times {|i| collector[i%3] +=3D }
=3D> 10



Ah, ok, now I see what you mean. I didn't consider this case, because
you are creating intermediate arrays every iteration. In my head I was
equating the +=3D for Fixnums with << for Arrays in this idiom, if you s= ee
what I mean.


That's what I would usually do. But you asked for the reason why the
default value setting was sufficient. So I demonstrated with a
mutable object and + - could have been anything else (BigDecimal#+ or
String#+ for example).

Cheers

robert

--=20
use.inject do |as, often| as.you_can - without end
 
C

Charles Calvert

2008/3/25 said:
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. I would pseudocode it as this:

cnt = Hash.new(0)
foreach (e in a)
{
cnt[e] += 1
}

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.
 
T

Todd Benson

2008/3/25, Jes=FAs Gabriel y Gal=E1n <[email protected]>:
a have an array array=3D["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 =3D %w{a b a c b a c c}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):007:0> h =3D Hash.new {|h,k| h[k] =3D 0}
=3D> {}
irb(main):008:0> a.each {|x| h[x] +=3D 1}
=3D> ["a", "b", "a", "c", "b", "a", "c", "c"]
irb(main):009:0> h
=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>3}

Here's another

Let's see if I understand this:

irb(main):001:0> a =3D %w{a b a c b a c c}
=3D> ["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]+=3D1; cnt}
=3D> {"a"=3D>3, "b"=3D>2, "c"=3D>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 c= nt
(which is a reference to the hash returned by "Hash.new"), it increments
the count whose key is the value of e. I would pseudocode it as this:

cnt =3D Hash.new(0)
foreach (e in a)
{
cnt[e] +=3D 1
}

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]+=3D1}

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.

You need to "inject" a Hash back into the block on each iteration,
which is the result of the block, which is the result of the last
statement inside the block.

If you leave that out...

h =3D a.inject(Hash.new(0)) {|k,v| k[v] +=3D 1}

...the next injection will be the result of the block, which will be
1, so on the next go around, you would be trying to...

1["a"] +=3D 1

...and thus the string error.

hth,
Todd
 
B

Bu Mihai

Paul said:
If you install the facets gem you can use "frequency"

e.g.
irb:> require 'rubygems'
=> false
irb:> require 'facets'
=> true
irb:> x = %w[a b d e e rkeke ele e ee e e el d]
=> ["a", "b", "d", "e", "e", "rkeke", "ele", "e", "ee", "e", "e", "el",
"d"]
irb:> x.frequency
=> {"ee"=>1, "a"=>1, "b"=>1, "d"=>2, "e"=>5, "el"=>1, "ele"=>1,
"rkeke"=>1}

Tnx a lot for this gem, it looks very interesting not just for solving
this issue.
 
R

Robert Klemme

2008/3/25 said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,197
Messages
2,571,040
Members
47,634
Latest member
RonnyBoelk

Latest Threads

Top