# Numbers of a record in an array

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

On Tue, Mar 25, 2008 at 10:09 AM, Bu Mihai [email protected]
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}

Hope this helps,

Jesus.

2008/3/25, Jesús Gabriel y Galán [email protected]:

=> {}
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

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

Jesús, 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

2008/3/25, Jesús Gabriel y Galán [email protected]:

=> {}
irb(main):002:0> a.inject(Hash.new(0)){|cnt,e| cnt[e]+=1; cnt}
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?

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 = Hash.new []
=> {}
irb(main):002:0> 10.times {|i| collector[i%3] += [i]}
=> 10
irb(main):003:0> collector
=> {0=>[0, 3, 6, 9], 1=>[1, 4, 7], 2=>[2, 5, 8]}

You can even freeze the default object

irb(main):007:0> collector = Hash.new([].freeze)
=> {}
irb(main):008:0> 10.times {|i| collector[i%3] += [i]}
=> 10
irb(main):009:0> collector
=> {0=>[0, 3, 6, 9], 1=>[1, 4, 7], 2=>[2, 5, 8]}

Kind regards

robert

On Tue, Mar 25, 2008 at 11:23 AM, Robert K.
[email protected] wrote:

irb(main):009:0> h

Jesús, 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.

On Tue, Mar 25, 2008 at 1:49 PM, Robert K.
[email protected] wrote:

2008/3/25, Jesús Gabriel y Galán [email protected]:

On Tue, Mar 25, 2008 at 11:23 AM, Robert K.
[email protected] wrote:

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 = Hash.new []
=> {}
irb(main):002:0> 10.times {|i| collector[i%3] += [i]}
=> 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 += for Fixnums with << for Arrays in this idiom, if you see
what I mean.

Thanks,

Jesus.

2008/3/25, Jesús Gabriel y Galán [email protected]:

(Fixnum#+ in this case) and uses assignment to place a new value on
you are creating intermediate arrays every iteration. In my head I was
equating the += for Fixnums with << for Arrays in this idiom, if you see
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

If you install the facets gem you can use “frequency”

e.g.

irb
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}

On Thu, Mar 27, 2008 at 9:44 PM, Charles C. [email protected]
wrote:

Here’s one way:

{

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 = a.inject(Hash.new(0)) {|k,v| k[v] += 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”] += 1

…and thus the string error.

hth,
Todd

Paul D. wrote:

If you install the facets gem you can use “frequency”

e.g.

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

On Tue, 25 Mar 2008 05:23:50 -0500, Robert K. wrote:

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.

On 28.03.2008 03:41, Charles C. wrote:

irb(main):006:0> a = %w{a b a c b a c c}

(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>

``````      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

On Mar 28, 11:39 am, jzakiya [email protected] wrote:

irb:> require ‘rubygems’
I installed facets 2.4.0 (the current latest) and tried to use the
‘frequency’ method shown in this example, but in doesn’t exist in this
version of facets.

I did ‘ri facets’ and it only returned ‘Enumerable#frequency’
This is using Linux (PCLOS) and Ruby 1.8.6-p114.

What version of facets does the ‘frequency’ method exist in, because
it isn’t in version 2.4.0?

Correction:
I did ‘ri frequency’ NOT ‘ri facets’

On Mar 27, 10:51 am, Paul D. [email protected] wrote:

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}

I installed facets 2.4.0 (the current latest) and tried to use the
‘frequency’ method shown in this example, but in doesn’t exist in this
version of facets.

I did ‘ri facets’ and it only returned ‘Enumerable#frequency’
This is using Linux (PCLOS) and Ruby 1.8.6-p114.

What version of facets does the ‘frequency’ method exist in, because
it isn’t in version 2.4.0?

A faster(running time) way is this

def freq2(a)
a_sorted=a.sort;temp=0;h=Hash.new(0);
a_sorted.uniq.each{|x|
h[x]=a_sorted.rindex(x)+1-temp;
temp+=h[x]
}
end

I did a small test and this method seems to running 5 times faster than
the
inject one!

start=Time.now; 1000.times{|x| freq1(a*x)}; stop=Time.now; puts
stop-start
16.413787

start=Time.now; 1000.times{|x| freq2(a*x)}; stop=Time.now; puts
stop-start
3.17855

This seemed counter intuitive as freq2 is doing a lot more than freq1.
Is inject that slow (or have I done something wrong)???

Piyush

On Mar 28, 11:39 am, jzakiya [email protected] wrote:

irb:> require ‘rubygems’
I installed facets 2.4.0 (the current latest) and tried to use the
‘frequency’ method shown in this example, but in doesn’t exist in this
version of facets.

I did ‘ri facets’ and it only returned ‘Enumerable#frequency’
This is using Linux (PCLOS) and Ruby 1.8.6-p114.

What version of facets does the ‘frequency’ method exist in, because
it isn’t in version 2.4.0?

OK, I found what is going on with facets and the ‘frequency’ method.

In facets 2.3.0 (2008/2/18) ‘frequency’ is a method under Enumerable,

require ‘rubygems’
require ‘facets’

The current facets 2.4.0 (2008/3/24) ‘frequency’ has been moved to the
‘probability.rb’ file under
the Enumerable module. So to load ‘frequency’ under facets 2.4.0 you
must do

require ‘rubygems’
require ‘facets/enumerable/probability.rb’

I would consider this a bug for breaking prior usage (by hiding the
method in probability.rb).

If you go to http://rubyforge.org/frs/?group_id=804&release_id=20470
and download the tar/zip files for each version you can see the
changes.

This is the facets source for ‘frequency’

def frequency
#probs = Hash.new(0)
#each do |e|
# probs[e] += 1
#end
#probs
inject(Hash.new(0)){|h,v| h[v]+=1; h}
end

Frequency exists in 2.4.0, but there appear to be some path problems w/
2.4.0.

Try uninstalling 2.4.0 and installing 2.3.0 instead.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.