Count occurences of vars in array

Hello, everyone.

Would be grateful if someone can tell, how can I do shortly (mb with one
method) from such example array

["a", "b", "a", "c", "c", "b", "b"]

The result
a => 2
b => 3
c => 2

So, to count number of occurances

···

--
Posted via http://www.ruby-forum.com/.

Hello,

Would be grateful if someone can tell, how can I do shortly (mb with one
method) from such example array

["a", "b", "a", "c", "c", "b", "b"]

The result
a => 2
b => 3
c => 2

So, to count number of occurences

arr = ["a", "b", "a", "c", "c", "b", "b"]

=> ["a", "b", "a", "c", "c", "b", "b"]

h = Hash.new(0) ; arr.each {|e| h[e] += 1}; p h

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

Cheers,

···

--
JJ Fleck
PCSI1 Lycée Kléber

h = Hash.new(0)
["a", "b", "a", "c", "c", "b", "b"].each {|s| h[s] += 1};

···

From: Vitaliy Yanchuk <fuksito@gmail.com>
Reply-To: <ruby-talk@ruby-lang.org>
Newsgroups: comp.lang.ruby
Date: Tue, 20 Jul 2010 22:47:27 +0900
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Subject: Count occurences of vars in array

Hello, everyone.

Would be grateful if someone can tell, how can I do shortly (mb with one
method) from such example array

["a", "b", "a", "c", "c", "b", "b"]

The result
a => 2
b => 3
c => 2

So, to count number of occurances
--
Posted via http://www.ruby-forum.com/\.

def owtdi( ary ); h = Hash.new(0); ary.each {|e| h[e] += 1}; h; end
def owtdi2( ary ); ary.inject(Hash.new(0)) {|h,e| h[e]+= 1; h}; end

def tmtowtdi( ary )
  ary = ary.sort; test_v = ! ary[0]; cary = ; kt = nil
  ary.each do |vv|
    if vv != test_v then
      cary << [test_v, kt] if kt
      test_v = vv; kt = 0
    end
    kt += 1
  end
  cary << [test_v, kt] if kt
  cary
end

rr = ["a", "b", "a", "c", "c", "b", "b"]
p owtdi( rr ), owtdi2( rr ), tmtowtdi( rr )
kt = 100_000
require "benchmark"
ow = ow2 = tmtow = nil
Benchmark.bmbm do|b|
  b.report("owtdi") { kt.times { ow = owtdi( rr ) } }
  b.report("tmtowtdi") { kt.times { tmtow = tmtowtdi( rr ) } }
end
puts; p ow, tmtow
__END__
{"a"=>2, "b"=>3, "c"=>2}
[["a", 2], ["b", 3], ["c", 2]]

               user system total real
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]
owtdi 3.572000 0.016000 3.588000 ( 4.422000)
tmtowtdi 4.883000 0.031000 4.914000 ( 5.819000)

ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-mingw32]
owtdi 2.558000 0.047000 2.605000 ( 3.243000)
tmtowtdi 1.545000 0.015000 1.560000 ( 1.943000)
  another 1.9.1 run: owtdi user = 2.293 and tmtowtdi user = 1.810;

jruby 1.5.0.RC1 (ruby 1.8.7 patchlevel 249) (2010-04-14 0b08bc7)
(Java HotSpot(TM) Client VM 1.6.0_14) [x86-java]
owtdi 1.980000 0.000000 1.980000 ( 1.979000)
tmtowtdi 1.523000 0.000000 1.523000 ( 1.522000)
I ought to point out that in a subsequent JRuby run
owtdi user = 1.625 and tmtowtdi user = 1.809,
and in another run owtdi user = 2.118 and tmtowtdi user = 1.987,
so quite variable! But there was quite a lot of apparently random and
purposeless disk i/o going on while the benchmarks were running. (Thank you,
Windows Vista!) So I would place even less reliance than usual on these
benchmarks. But using inject does seem significantly slower, especially so
using 1.8.6.

···

On Tue, Jul 20, 2010 at 2:47 PM, Vitaliy Yanchuk <fuksito@gmail.com> wrote:

... Would be grateful if someone can tell, how can I do shortly (mb with
one
method) from such example array
  ["a", "b", "a", "c", "c", "b", "b"]
The result: a => 2, b => 3, c => 2. So, to count number of occurances.

Jean-Julien Fleck, thanks.
Maybe have an idea of a one-line version? :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

I know this isn't what the original post was about...but...

The variability is probably due partially to the jitting behavior of
the JVM; it's hard to know when the JVM will hit its stable state.

FWIW, a longer run will get even faster, and passing --server to JRuby
boosts it too:

jruby Java 6 server, fifth iteration:
                user system total real
owtdi 0.223000 0.000000 0.223000 ( 0.223000)
tmtowtdi 0.223000 0.000000 0.223000 ( 0.223000)

ruby 1.9.2 trunkish:
                user system total real
owtdi 0.470000 0.010000 0.480000 ( 0.481433)
tmtowtdi 0.350000 0.000000 0.350000 ( 0.350423)

I don't have an explanation for the performance difference; the logic
involved should be pretty native-lib heavy.

- Charlie

···

On Tue, Jul 20, 2010 at 8:32 AM, Colin Bartlett <colinb2r@googlemail.com> wrote:

jruby 1.5.0.RC1 (ruby 1.8.7 patchlevel 249) (2010-04-14 0b08bc7)
(Java HotSpot(TM) Client VM 1.6.0_14) [x86-java]
owtdi 1.980000 0.000000 1.980000 ( 1.979000)
tmtowtdi 1.523000 0.000000 1.523000 ( 1.522000)
I ought to point out that in a subsequent JRuby run
owtdi user = 1.625 and tmtowtdi user = 1.809,
and in another run owtdi user = 2.118 and tmtowtdi user = 1.987,
so quite variable! But there was quite a lot of apparently random and
purposeless disk i/o going on while the benchmarks were running. (Thank you,
Windows Vista!) So I would place even less reliance than usual on these
benchmarks. But using inject does seem significantly slower, especially so
using 1.8.6.

Well: quite the same using inject:

arr.inject(Hash.new(0)) {|h,e| h[e]+= 1; h}

It all depends on what you call 'one-line' :o)

Cheers,

···

2010/7/20 Vitaliy Yanchuk <fuksito@gmail.com>:

Jean-Julien Fleck, thanks.
Maybe have an idea of a one-line version? :slight_smile:

--
JJ Fleck
PCSI1 Lycée Kléber

Try this or something like this.
I'm very sleepy ZZZZZZZZZZZ

arr = ["a", "b", "a", "c", "c", "b", "b"]
p Hash[*(arr.uniq.map{|x| [x,arr.select{|y| y == x}.length]}).flatten]

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

Harry

···

On Tue, Jul 20, 2010 at 11:25 PM, Vitaliy Yanchuk <fuksito@gmail.com> wrote:

Jean-Julien Fleck, thanks.
Maybe have an idea of a one-line version? :slight_smile:

Jean-Julien Fleck wrote:

···

2010/7/20 Vitaliy Yanchuk <fuksito@gmail.com>:

Jean-Julien Fleck, thanks.
Maybe have an idea of a one-line version? :slight_smile:

Well: quite the same using inject:

arr.inject(Hash.new(0)) {|h,e| h[e]+= 1; h}

It all depends on what you call 'one-line' :o)

Cheers,

Wow, Inject is cool method, thanks !
In my mind one-line is that dows not have semi-coloms or new lines of
course
--
Posted via http://www.ruby-forum.com/\.

Nice!

···

arr.inject(Hash.new(0)) {|h,e| h[e]+= 1; h}

--
JJ Fleck
PCSI1 Lycée Kléber

p Hash[*(arr.uniq.map{|x| [x,arr.select{|y| y == x}.length]}).flatten]

Harry showed the way:

Hash[arr.group_by {|o| o}.collect{|k,v| [k,v.size]}]

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

Cheers,

···

2010/7/20 Harry Kakueki <list.push@gmail.com>:

--
JJ Fleck
PCSI1 Lycée Kléber

Soo... that has a semi-colon and isn't then a one-liner?? :wink:

-Rob

Rob Biedenharn
Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/
rab@GaslightSoftware.com http://GaslightSoftware.com/

···

On Jul 20, 2010, at 10:58 AM, Vitaliy Yanchuk wrote:

Jean-Julien Fleck wrote:

2010/7/20 Vitaliy Yanchuk <fuksito@gmail.com>:

Jean-Julien Fleck, thanks.
Maybe have an idea of a one-line version? :slight_smile:

Well: quite the same using inject:

arr.inject(Hash.new(0)) {|h,e| h[e]+= 1; h}

It all depends on what you call 'one-line' :o)

Cheers,

Wow, Inject is cool method, thanks !
In my mind one-line is that dows not have semi-coloms or new lines of
course
--

Check this out

['a', 'b', 'a', 'b', 'c', 'c',
'c'].group_by{|o|o}.collect{|k,v|{k,v.size}}.to_yaml"

Result:
- a: 2
- b: 2
- c: 3

···

--
Posted via http://www.ruby-forum.com/.

Rob Biedenharn wrote:

Soo... that has a semi-colon and isn't then a one-liner?? :wink:

Yeah, not perfectly one-liner. But it is without dot-chain breaking, not
bad too :slight_smile:

···

--
Posted via http://www.ruby-forum.com/\.

If that really bothers anyone...

Hash.new(0).tap{|h| arr.each{|e| h[e] += 1} }

···

On Tuesday, July 20, 2010 10:05:27 am Rob Biedenharn wrote:

On Jul 20, 2010, at 10:58 AM, Vitaliy Yanchuk wrote:
> Jean-Julien Fleck wrote:
>> 2010/7/20 Vitaliy Yanchuk <fuksito@gmail.com>:
>>> Jean-Julien Fleck, thanks.
>>> Maybe have an idea of a one-line version? :slight_smile:
>>
>> Well: quite the same using inject:
>>
>> arr.inject(Hash.new(0)) {|h,e| h[e]+= 1; h}
>>
>> It all depends on what you call 'one-line' :o)
>>
>> Cheers,
>
> Wow, Inject is cool method, thanks !
> In my mind one-line is that dows not have semi-coloms or new lines of
> course

Soo... that has a semi-colon and isn't then a one-liner?? :wink:

That would be a real one-liner if I could recall how to convert
elegantly an array of size2 arrays into an hash:

arr.group_by {|o| o}.collect{|k,v| [k,v.size]}

Cheers,

···

2010/7/20 Vitaliy Yanchuk <fuksito@gmail.com>:

Rob Biedenharn wrote:

Soo... that has a semi-colon and isn't then a one-liner?? :wink:

Yeah, not perfectly one-liner. But it is without dot-chain breaking, not
bad too :slight_smile:

--
JJ Fleck
PCSI1 Lycée Kléber

Hi --

···

On Wed, 21 Jul 2010, Vitaliy Yanchuk wrote:

Rob Biedenharn wrote:

Soo... that has a semi-colon and isn't then a one-liner?? :wink:

Yeah, not perfectly one-liner. But it is without dot-chain breaking, not
bad too :slight_smile:

In Ruby 1.9 there's Enumerator#with_object, which is a nice way to avoid
that "; h" thing that you have to do in #inject to make it return the
accumulator:

   count_hash = a.each.with_object(Hash.new(0)) {|e, hash| hash[e] += 1 }

David

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

   The Ruby training with Black/Brown/McAnally
   Compleat Philadelphia, PA, October 1-2, 2010
   Rubyist http://www.compleatrubyist.com

David Masover wrote:

Hash.new(0).tap{|h| arr.each{|e| h[e] += 1} }

Yes ! I always use this construct. Instead of

obj = Klass.new
# do something to obj
obj

I use

Klass.new do |obj|
# do something to obj
end

which, at least to me, has a better look.

_md

···

--
Posted via http://www.ruby-forum.com/\.