From: "Abinoam Jr." Date: 2012-01-17T10:05:33+09:00 Subject: Re: uniq with count; better way? On Mon, Jan 16, 2012 at 9:22 PM, Abinoam Jr. wrote: > On Mon, Jan 16, 2012 at 1:48 PM, Magnus Holm wrote: >> On Mon, Jan 16, 2012 at 17:04, Adam Prescott wrote: >>> On Mon, Jan 16, 2012 at 16:00, Sigurd wrote: >>> >>>> [4,5,6,4,5,6,6,7].inject(Hash.new(0)) {|res, x| res[x] += 1; res } >>>> >>> >>> I think this is a misuse of inject, personally, every time I see it. It's >>> harder to read and it doesn't give the feeling of actually "reducing" >>> (inject's alias) the array down to one thing. The required `; res` is a >>> sign of that. Compare: >>> >>> [1, 2, 3, 4].inject(5) { |a, b| a + b } >> >> There's always each_with_object, although it's a little long: >> >>  [4,5,6,4,5,6,6,7].each_with_object(Hash.new(0)) { |x, res| res[x] += 1 } >> > > I think Magnus Holm is the clearest (IMHO, yes, it's just a taste and > humble opinion.). > > [4,5,6,4,5,6,6,7].each_with_object(Hash.new(0)) {|num, hsh| hsh[num] += 1} > > Another way (not better) I remember is... > > Hash[ [4,5,6,4,5,6,6,7].sort.chunk {|n| n}.map {|ix, els| [ix, els.size] } ] > > See: http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-chunk > > It also can be... clearer?!? > > Hash[ [4,5,6,4,5,6,6,7].group_by {|n| n}.map {|ix, els| [ix, els.size] } ] > > Perhaps something like this (same as Magnus Holm) just hiding the > complexity into the method. > > class Array >  def totalize_to_hash >    hsh = Hash.new(0) >    self.each do |n| >      hsh[n] += 1 >    end >    hsh >  end > end > > [4,5,6,4,5,6,6,7].totalize_to_hash > > Abinoam Jr. Some benchmark results... n = 100_000 Benchmark.bm(15) do |b| b.report("Ralph Shneiver:") { n.times { a = [4,5,6,4,5,6,6,7]; result = Hash.new(0); a.each { |x| result[x] += 1 }; result} } b.report("Sigurd:") { n.times { [4,5,6,4,5,6,6,7].inject(Hash.new(0)) {|res, x| res[x] += 1; res } } } b.report("Keinich #1") { n.times { Hash[a.group_by{|n|n}.map{|k, v|[k, v.size]}] } } b.report("Keinich #2") { n.times { Hash.new(0).tap{|h|a.each{|n|h[n] += 1}} } } b.report("Magnus Holm:") { n.times { [4,5,6,4,5,6,6,7].each_with_object(Hash.new(0)) { |x, res| res[x] += 1 } } } b.report("Abinoam #1:") { n.times { Hash[ [4,5,6,4,5,6,6,7].sort.chunk {|n| n}.map {|ix, els| [ix, els.size] } ] } } end user system total real Ralph Shneiver: 0.290000 0.000000 0.290000 ( 0.259640) Sigurd: 0.320000 0.000000 0.320000 ( 0.289873) Keinich #1 0.560000 0.000000 0.560000 ( 0.497736) Keinich #2 0.280000 0.000000 0.280000 ( 0.250843) Magnus Holm: 0.310000 0.000000 0.310000 ( 0.283344) Abinoam #1: 1.140000 0.000000 1.140000 ( 1.042744) Abinoam Jr.