From: Harry Kakueki on 20 Jul 2010 11:26 On Tue, Jul 20, 2010 at 11:25 PM, Vitaliy Yanchuk wrote:> Jean-Julien Fleck, thanks. > Maybe have an idea of a one-line version? :) > 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 From: Colin Bartlett on 20 Jul 2010 11:32 [Note: parts of this message were removed to make it a legal post.] On Tue, Jul 20, 2010 at 2:47 PM, Vitaliy Yanchuk 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. 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. From: Jean-Julien Fleck on 20 Jul 2010 11:41 2010/7/20 Harry Kakueki :> 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, -- JJ Fleck PCSI1 Lycée Kléber From: Vitaliy Yanchuk on 20 Jul 2010 15:28 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/. From: David A. Black on 20 Jul 2010 16:56 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?? ;-) > > Yeah, not perfectly one-liner. But it is without dot-chain breaking, not > bad too :) 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 First  |  Prev  |  Next  |  Last