From: Robert Klemme Date: 2012-01-17T16:24:21+09:00 Subject: Re: uniq with count; better way? On Mon, Jan 16, 2012 at 10:03 PM, Sigurd wrote: > > On Jan 16, 2012, at 10:15 PM, Robert Klemme wrote: > >> Please do not top post. >> >> On Mon, Jan 16, 2012 at 7:08 PM, Sigurd wrote: >>> it seems not quite accurate to me because of block. inject uses convention that the last statement in method is a return. >>>  Therefore it's more natural to use short inject method definitions: either a.inject(5, :+) either 5 + a.inject(:+).  If the memo return in proc would be unnatural the inject won't pass it to the proc explicitly. >> >> ??? > > The argue was about the explicit memo returns so on a given sample I tried to show that that sample do not necessarily need to use blocks. But I see no problem to explicitly return value if i was passed to that block. Yes, sometimes it looks ugly, sometimes, especially with tap, it looks pretty nice. Funny thing is, that when you do x.inject(&:+) #inject actually sees a block. This is just a shorthand notation for doing x.inject {|a,b| a+b}. See doc of #to_proc and here: irb(main):028:0> o = Object.new => # irb(main):029:0> def o.to_proc; lambda {|*a| printf "block %p\n", a} end => nil irb(main):030:0> def f;if block_given? then yield else puts "no block" end end => nil irb(main):031:0> f() { puts 123 } 123 => nil irb(main):032:0> f no block => nil irb(main):033:0> f &o block [] => nil irb(main):034:0> f(&o) block [] => nil >>> On the other side I'm not a proponent of the crazy injects that could be barely understood. I think in this case inject could be used easily as well as the other solutions provided. >>> >>> On Jan 16, 2012, at 6:14 PM, Adam Prescott wrote: >>> >>>> On Jan 16, 2012 4:09 PM, "Sigurd" wrote: >>>>> >>>>> You example is not accurate though: >>>>> >>>>> 5 +  [1, 2, 3, 4].reduce(&:+) >> >> Can you please again explain what is not accurate about Adam's piece >> of code?  Are you aware of the two different behaviors of #inject? >> > > Technically it's good. My argument was not that the code is not functional or doing something in a wrong way or that syntax is unacceptable. The point i have is that Adams code is not the best example illustrating that the explicit inject block returns is the sign of incorrect inject use or let's call it "code smell". I'm not against that particular piece of code, it's just someone is wrong in internet again :) Aha. I would not have called that "not accurate". >> irb(main):001:0> [[1,2,3],[1],[]].each do |a| >> irb(main):002:1* p a, a.inject(&:+), a.inject(0, &:+) >> irb(main):003:1> end >> [1, 2, 3] >> 6 >> 6 >> [1] >> 1 >> 1 >> [] >> nil >> 0 >> => [[1, 2, 3], [1], []] >> >> Both have their use and it depends on the use case which you pick. > > I don't know can this be called different behavior. Inject use the first value of collection if it's not set explicitly so it's like particular case of inject, but i'm ok with the two different cases as well. It is different behavior because the block is invoked different number of times. And behavior is controlled by the fact whether an argument is passed to #inject or not: irb(main):016:0> [[1,2,3],[1],[]].each do |a| irb(main):017:1* p a irb(main):018:1> p a.inject {|x,y| printf "block 1: %p, %p\n", x, y;x+y}, irb(main):019:1* a.inject(0) {|x,y| printf "block 2: %p, %p\n", x, y;x+y}, irb(main):020:1* a.inject(nil) {|x,y| printf "block 3: %p, %p\n", x, y;x.to_i+y} irb(main):021:1> end [1, 2, 3] block 1: 1, 2 block 1: 3, 3 block 2: 0, 1 block 2: 1, 2 block 2: 3, 3 block 3: nil, 1 block 3: 1, 2 block 3: 3, 3 6 6 6 [1] block 2: 0, 1 block 3: nil, 1 1 1 1 [] nil 0 nil => [[1, 2, 3], [1], []] Cheers robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/