[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

equivalent injecting implementations?

Trans

11/10/2007 1:15:00 AM

Are these strictly equivalent? I get the feeling no, but I haven't
been able to demonstrate it yet.

def injecting(s)
inject(s) do |k, i|
yield(k, i); k
end
end

def injecting(res, &block)
([res]*length).zip(to_a).each(&block)
res
end

Thanks,
T.


13 Answers

Rick DeNatale

11/10/2007 1:50:00 PM

0

On 11/9/07, Trans <transfire@gmail.com> wrote:
> Are these strictly equivalent? I get the feeling no, but I haven't
> been able to demonstrate it yet.
>
> def injecting(s)
> inject(s) do |k, i|
> yield(k, i); k
> end
> end
>
> def injecting(res, &block)
> ([res]*length).zip(to_a).each(&block)
> res
> end
>
> Thanks,
> T.

I can't see how in general they can be.

In which class or module are you defining these? Since you are using
inject and each, I'm guessing that it's either Enumerable or some
subclass,

But then depending on which subclass you don't have a length method so...

Perhaps some more context would help.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Trans

11/10/2007 2:38:00 PM

0



On Nov 10, 8:50 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:
> On 11/9/07, Trans <transf...@gmail.com> wrote:
>
>
>
> > Are these strictly equivalent? I get the feeling no, but I haven't
> > been able to demonstrate it yet.
>
> > def injecting(s)
> > inject(s) do |k, i|
> > yield(k, i); k
> > end
> > end
>
> > def injecting(res, &block)
> > ([res]*length).zip(to_a).each(&block)
> > res
> > end
>
> > Thanks,
> > T.
>
> I can't see how in general they can be.
>
> In which class or module are you defining these? Since you are using
> inject and each, I'm guessing that it's either Enumerable or some
> subclass,
>
> But then depending on which subclass you don't have a length method so...
>
> Perhaps some more context would help.

Oh sorry, I meant to put that. These are Enumerable methods.

T.


Rick DeNatale

11/10/2007 3:50:00 PM

0

On Nov 10, 2007 9:37 AM, Trans <transfire@gmail.com> wrote:
>
>
> On Nov 10, 8:50 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:
> > On 11/9/07, Trans <transf...@gmail.com> wrote:
> >
> >
> >
> > > Are these strictly equivalent? I get the feeling no, but I haven't
> > > been able to demonstrate it yet.
> >
> > > def injecting(s)
> > > inject(s) do |k, i|
> > > yield(k, i); k
> > > end
> > > end
> >
> > > def injecting(res, &block)
> > > ([res]*length).zip(to_a).each(&block)
> > > res
> > > end
> >
> > > Thanks,
> > > T.
> >
> > I can't see how in general they can be.
> >
> > In which class or module are you defining these? Since you are using
> > inject and each, I'm guessing that it's either Enumerable or some
> > subclass,
> >
> > But then depending on which subclass you don't have a length method so...
> >
> > Perhaps some more context would help.
>
> Oh sorry, I meant to put that. These are Enumerable methods.
>
module Enumerable
def injecting(s)
inject(s) do |k, i|
yield(k, i); k
end
end

def injecting2(res, &block)
([res]*length).zip(to_a).each(&block)
res
end
end

(1..3).injecting(0) {|k,i| k + i} # => 0
(1..3).injecting2(0) {|k,i| k + i} # =>
# ~> -:9:in `injecting2': undefined local variable or method `length'
for 1..3:Range (NameError)
# ~> from -:15

Which illustrates my point.

Just what is injecting supposed to mean anyway? The first
implementation uses inject and takes a two argument block like inject
does, but seems to be going out of it's way to disregard the value of
the argument block.

This doesn't seem much like inject to me.



--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Robert Klemme

11/10/2007 4:43:00 PM

0

On 10.11.2007 16:50, Rick DeNatale wrote:
> On Nov 10, 2007 9:37 AM, Trans <transfire@gmail.com> wrote:
>>
>> On Nov 10, 8:50 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:
>>> On 11/9/07, Trans <transf...@gmail.com> wrote:
>>>
>>>
>>>
>>>> Are these strictly equivalent? I get the feeling no, but I haven't
>>>> been able to demonstrate it yet.
>>>> def injecting(s)
>>>> inject(s) do |k, i|
>>>> yield(k, i); k
>>>> end
>>>> end
>>>> def injecting(res, &block)
>>>> ([res]*length).zip(to_a).each(&block)
>>>> res
>>>> end
>>>> Thanks,
>>>> T.
>>> I can't see how in general they can be.
>>>
>>> In which class or module are you defining these? Since you are using
>>> inject and each, I'm guessing that it's either Enumerable or some
>>> subclass,
>>>
>>> But then depending on which subclass you don't have a length method so...
>>>
>>> Perhaps some more context would help.
>> Oh sorry, I meant to put that. These are Enumerable methods.
>>
> module Enumerable
> def injecting(s)
> inject(s) do |k, i|
> yield(k, i); k
> end
> end
>
> def injecting2(res, &block)
> ([res]*length).zip(to_a).each(&block)
> res
> end
> end
>
> (1..3).injecting(0) {|k,i| k + i} # => 0
> (1..3).injecting2(0) {|k,i| k + i} # =>
> # ~> -:9:in `injecting2': undefined local variable or method `length'
> for 1..3:Range (NameError)
> # ~> from -:15
>
> Which illustrates my point.
>
> Just what is injecting supposed to mean anyway? The first
> implementation uses inject and takes a two argument block like inject
> does, but seems to be going out of it's way to disregard the value of
> the argument block.
>
> This doesn't seem much like inject to me.

Even if you do use it on an Array the two are not equivalent since the
second variant does not propagate the block result. The second variant
works only when you only modify something (say a Hash).

I don't see the point in having the first one since it reimplements
#inject - but without the subtle specialty of different behavior when no
args are passed to it.

Kind regards

robert

Ezra Zygmuntowicz

11/10/2007 9:23:00 PM

0


On Nov 10, 2007, at 7:50 AM, Rick DeNatale wrote:

> On Nov 10, 2007 9:37 AM, Trans <transfire@gmail.com> wrote:
>>
>>
>> On Nov 10, 8:50 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:
>>> On 11/9/07, Trans <transf...@gmail.com> wrote:
>>>
>>>
>>>
>>>> Are these strictly equivalent? I get the feeling no, but I haven't
>>>> been able to demonstrate it yet.
>>>
>>>> def injecting(s)
>>>> inject(s) do |k, i|
>>>> yield(k, i); k
>>>> end
>>>> end
>>>
>>>> def injecting(res, &block)
>>>> ([res]*length).zip(to_a).each(&block)
>>>> res
>>>> end
>>>
>>>> Thanks,
>>>> T.
>>>
>>> I can't see how in general they can be.
>>>
>>> In which class or module are you defining these? Since you are
>>> using
>>> inject and each, I'm guessing that it's either Enumerable or some
>>> subclass,
>>>
>>> But then depending on which subclass you don't have a length
>>> method so...
>>>
>>> Perhaps some more context would help.
>>
>> Oh sorry, I meant to put that. These are Enumerable methods.
>>
> module Enumerable
> def injecting(s)
> inject(s) do |k, i|
> yield(k, i); k
> end
> end
>
> def injecting2(res, &block)
> ([res]*length).zip(to_a).each(&block)
> res
> end
> end
>
> (1..3).injecting(0) {|k,i| k + i} # => 0
> (1..3).injecting2(0) {|k,i| k + i} # =>
> # ~> -:9:in `injecting2': undefined local variable or method `length'
> for 1..3:Range (NameError)
> # ~> from -:15
>
> Which illustrates my point.
>
> Just what is injecting supposed to mean anyway? The first
> implementation uses inject and takes a two argument block like inject
> does, but seems to be going out of it's way to disregard the value of
> the argument block.
>
> This doesn't seem much like inject to me.


injecting is similar to returning in rails. There is a common pattern
of accumulating a hash via inject that looks like this:

[1,2,3].inject({}) { |memo,n| memo[n] = n ; memo}
#=> {1=>1, 3=>3,2=>2}

Note the ugly trailing ;memo, this is so the fll accumulated hash is
the final return result.

injecting is just a little bit nicer way to do the same thing:

[1,2,3].injecting({}) { |memo,n| memo[n] = n }
#=> {1=>1, 3=>3,2=>2}

Cheers-
-Ezra



Trans

11/10/2007 10:03:00 PM

0



On Nov 10, 10:50 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:
> On Nov 10, 2007 9:37 AM, Trans <transf...@gmail.com> wrote:
>
>
>
> > On Nov 10, 8:50 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:
> > > On 11/9/07, Trans <transf...@gmail.com> wrote:
>
> > > > Are these strictly equivalent? I get the feeling no, but I haven't
> > > > been able to demonstrate it yet.
>
> > > > def injecting(s)
> > > > inject(s) do |k, i|
> > > > yield(k, i); k
> > > > end
> > > > end
>
> > > > def injecting(res, &block)
> > > > ([res]*length).zip(to_a).each(&block)
> > > > res
> > > > end
>
> > > > Thanks,
> > > > T.
>
> > > I can't see how in general they can be.
>
> > > In which class or module are you defining these? Since you are using
> > > inject and each, I'm guessing that it's either Enumerable or some
> > > subclass,
>
> > > But then depending on which subclass you don't have a length method so...
>
> > > Perhaps some more context would help.
>
> > Oh sorry, I meant to put that. These are Enumerable methods.
>
> module Enumerable
> def injecting(s)
> inject(s) do |k, i|
> yield(k, i); k
> end
> end
>
> def injecting2(res, &block)
> ([res]*length).zip(to_a).each(&block)
> res
> end
> end
>
> (1..3).injecting(0) {|k,i| k + i} # => 0
> (1..3).injecting2(0) {|k,i| k + i} # =>
> # ~> -:9:in `injecting2': undefined local variable or method `length'
> for 1..3:Range (NameError)
> # ~> from -:15
>
> Which illustrates my point.

Ah. sorry. I missed what you were getting at there. Yea, right off the
bat length isn't support, so it would have to apply to Array instead.
I was really just curious how they differ in result because they were
outputing the same thing when I rand some cases on it.

> Just what is injecting supposed to mean anyway? The first
> implementation uses inject and takes a two argument block like inject
> does, but seems to be going out of it's way to disregard the value of
> the argument block.
>
> This doesn't seem much like inject to me.

It's basically the the same, but you don't need to pass the memo back
each time.

T.


Trans

11/10/2007 10:05:00 PM

0



On Nov 10, 11:45 am, Robert Klemme <shortcut...@googlemail.com> wrote:

> Even if you do use it on an Array the two are not equivalent since the
> second variant does not propagate the block result. The second variant
> works only when you only modify something (say a Hash).

Ah, that's what I was wondering about. It has to be inplace
modifications to get the same output. Ok.Thanks.

> I don't see the point in having the first one since it reimplements
> #inject - but without the subtle specialty of different behavior when no
> args are passed to it.

Yea. it's minor, but some people like it. Actually just using #each is
much faster than inject or injecting. So speed freaks, forget that
silly inject!

T.


Rick DeNatale

11/11/2007 2:50:00 PM

0

On Nov 10, 2007 4:23 PM, Ezra Zygmuntowicz <ezmobius@gmail.com> wrote:
>
>
> On Nov 10, 2007, at 7:50 AM, Rick DeNatale wrote:

> > Just what is injecting supposed to mean anyway? The first
> > implementation uses inject and takes a two argument block like inject
> > does, but seems to be going out of it's way to disregard the value of
> > the argument block.
> >
> > This doesn't seem much like inject to me.
>
>
> injecting is similar to returning in rails.

>There is a common pattern
> of accumulating a hash via inject that looks like this:
>
> [1,2,3].inject({}) { |memo,n| memo[n] = n ; memo}
> #=> {1=>1, 3=>3,2=>2}
>
> Note the ugly trailing ;memo, this is so the fll accumulated hash is
> the final return result.
>
> injecting is just a little bit nicer way to do the same thing:
>
> [1,2,3].injecting({}) { |memo,n| memo[n] = n }
> #=> {1=>1, 3=>3,2=>2}

Yes, I suspected that this was what Trans was trying to do, but since
the second proposed 'maybe equivalent' implementation didn't seem to
be doing the same thing, I was probing for what he really wanted.

Having said that, and played a bit with the concept. I'm not sure how
useful an injecting method (at least with that name is).

As Robert Klemme points out, it breaks depending on what you are
injecting. And it's subject to "cargo culting."

module Enumerable
def injecting(obj, &blk)
inject(obj) { |mem, var| yield(mem, var); mem }
end
end

As Ezra points out:

[1,2,3].inject({}) { |memo,n| memo[n] = n ; memo} # => {1=>1, 2=>2, 3=>3}
[1,2,3].injecting({}) { |memo,n| memo[n] = n} # => {1=>1, 2=>2, 3=>3}

But this only works because the block has a side-effect on the memo
object. And yes, in cases like this each instead of inject will have
the same side effects.

[1,2,3].inject(0) { |memo,n| memo + n} # => 6
[1,2,3].injecting(0) { |memo,n| memo + n} # => 0

Here's where the cargo cult danger comes in. Someone who comes across
'injecting' without understanding it might run into things like this.

So while the idea of an injecting method seems nice, I'm not enamored
of the name.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

David A. Black

11/11/2007 2:55:00 PM

0

Hi --

On Sun, 11 Nov 2007, Rick DeNatale wrote:

> So while the idea of an injecting method seems nice, I'm not enamored
> of the name.

How about inject! ? :-)


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing With Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.r... for details!

Phrogz

11/11/2007 3:38:00 PM

0

On Nov 10, 1:23 pm, Ezra Zygmuntowicz <ezmob...@gmail.com> wrote:
> injecting is similar to returning in rails. There is a common pattern
> of accumulating a hash via inject that looks like this:
>
> [1,2,3].inject({}) { |memo,n| memo[n] = n ; memo}
> #=> {1=>1, 3=>3,2=>2}
>
> Note the ugly trailing ;memo, this is so the fll accumulated hash is
> the final return result.

Note that you can avoid the trailing memo with this:
[1,2,3].inject({}) { |memo,n| memo.update n=>n }
....but it's a good deal slower:

a = (1..10_000).to_a
N = 500

require 'benchmark'
Benchmark.bmbm{ |x|
x.report( 'set' ){
N.times{
a.inject({}){ |memo,n| memo[n] = n; memo }
}
}
x.report( 'update' ){
N.times{
a.inject({}){ |memo,n| memo.update n=>n }
}
}
}

Rehearsal ------------------------------------------
set 5.860000 0.010000 5.870000 ( 5.981301)
update 11.830000 0.020000 11.850000 ( 11.865100)
-------------------------------- total: 17.720000sec

user system total real
set 5.960000 0.040000 6.000000 ( 6.011882)
update 11.850000 0.070000 11.920000 ( 11.925828)