Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   FirstEachLast, an extension to the Enumerable module. (http://www.velocityreviews.com/forums/t816042-firsteachlast-an-extension-to-the-enumerable-module.html)

John Carter 08-09-2004 05:38 AM

FirstEachLast, an extension to the Enumerable module.
 
I know somewhere is a collection of extensions to the enumerable module.

Is the rubygarden page
http://www.rubygarden.org/ruby?Stand...ons/Enumerable
the only one?

Anyway, I have just added FirstEachLast to that.

Use it like so...

require 'FirstEachLast'

def test_first_each_last(any_enumerable_object)
result = nil
count =
any_enumerable_object.first_each_last( proc {|first|
result = "First #{first}"
},
proc {|i|
result += " then #{i},"
},
proc {|last|
result += " and last of all #{last}"
},
proc {|| result = 'Empty!'}

puts count
puts result
end

test_first_each_last( [1,2,3,4])
test_first_each_last( [])

Will result in the following output...
4
First 1 then 2, then 3, and last of all 4
0
Empty!



John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

The universe is absolutely plastered with the dashed lines exactly one
space long.



Robert Klemme 08-09-2004 07:16 AM

Re: FirstEachLast, an extension to the Enumerable module.
 

"John Carter" <john.carter@tait.co.nz> schrieb im Newsbeitrag
news:Pine.LNX.4.61.0408091724450.32554@parore.tait .co.nz...
> I know somewhere is a collection of extensions to the enumerable module.
>
> Is the rubygarden page
> http://www.rubygarden.org/ruby?Stand...ons/Enumerable
> the only one?
>
> Anyway, I have just added FirstEachLast to that.
>
> Use it like so...
>
> require 'FirstEachLast'
>
> def test_first_each_last(any_enumerable_object)
> result = nil
> count =
> any_enumerable_object.first_each_last( proc {|first|
> result = "First

#{first}"
> },
> proc {|i|
> result += " then #{i},"
> },
> proc {|last|
> result += " and last of

all #{last}"
> },
> proc {|| result =

'Empty!'}
>
> puts count
> puts result
> end
>
> test_first_each_last( [1,2,3,4])
> test_first_each_last( [])
>
> Will result in the following output...
> 4
> First 1 then 2, then 3, and last of all 4
> 0
> Empty!


Nice output, but what do you need that for?

robert


John Carter 08-09-2004 09:23 PM

Re: FirstEachLast, an extension to the Enumerable module.
 
On Mon, 9 Aug 2004, Robert Klemme wrote:

> Nice output, but what do you need that for?


Mostly output to other tools, like gnuplot, or for reports. Most time
enum._to_a.join(",") does the job perfectly. However, there are the odd
time when that routine is just neat.


John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

The universe is absolutely plastered with the dashed lines exactly one
space long.



Robert Klemme 08-10-2004 06:45 AM

Re: FirstEachLast, an extension to the Enumerable module.
 

"John Carter" <john.carter@tait.co.nz> schrieb im Newsbeitrag
news:Pine.LNX.4.61.0408100907530.1791@parore.tait. co.nz...
> On Mon, 9 Aug 2004, Robert Klemme wrote:
>
> > Nice output, but what do you need that for?

>
> Mostly output to other tools, like gnuplot, or for reports. Most time
> enum._to_a.join(",") does the job perfectly. However, there are the odd
> time when that routine is just neat.


Hm, sounds to me like it was not general enough to include it in
Enumerable. Before I see that method I'd prefer to have size and empty?
in Enumerable. Just my 0.02 EUR...

Regards

robert


Martin DeMello 08-10-2004 08:45 AM

Re: FirstEachLast, an extension to the Enumerable module.
 
Robert Klemme <bob.news@gmx.net> wrote:
>
> Hm, sounds to me like it was not general enough to include it in
> Enumerable. Before I see that method I'd prefer to have size and empty?
> in Enumerable. Just my 0.02 EUR...


Can empty? be reliably implemented in terms of each for every
enumerable? I can't think of an obvious problem with it, but that
doesn't mean there isn't one.

martin

Alexander Kellett 08-10-2004 09:13 AM

Re: FirstEachLast, an extension to the Enumerable module.
 
On Tue, Aug 10, 2004 at 03:46:17PM +0900, Robert Klemme wrote:
> Hm, sounds to me like it was not general enough to include it in
> Enumerable. Before I see that method I'd prefer to have size and empty?
> in Enumerable. Just my 0.02 EUR...


personally the idea of having a method taking 4 procs
in the stdlib is just a bit strange. i'd prefer to see
a generic set of methods that are somehow mixedin to
the values that a Enumerable yields, therefore allowing
things like val.last? or first? or even a generic
val.enum_index to replace the each_with_index rubbish.
i've no idea how to solve this neatly unfortunately as
extend'ing the objects that are yield'ed of course will
have sideeffects... though most of the side effects that
will cause problems shouldn't happen at all, e.g people
calling is_a? a lot will have problems... i do this
and yet i don't have an exception to such an extension...
but this:

blah.each {
|element|
pos = blah.index element
puts blah[pos-1]
puts element
}

is soooooo uggllyyy... not to mention inefficient...
i'd just loooveeee to see a element.previous_in_enum...

cheers,
Alex



Robert Klemme 08-10-2004 09:33 AM

empty? and size in Enumerable (was: Re: FirstEachLast, an extension to the Enumerable module.)
 

"Martin DeMello" <martindemello@yahoo.com> schrieb im Newsbeitrag
news:xW%Rc.68814$gE.48438@pd7tw3no...
> Robert Klemme <bob.news@gmx.net> wrote:
> >
> > Hm, sounds to me like it was not general enough to include it in
> > Enumerable. Before I see that method I'd prefer to have size and

empty?
> > in Enumerable. Just my 0.02 EUR...

>
> Can empty? be reliably implemented in terms of each for every
> enumerable? I can't think of an obvious problem with it, but that
> doesn't mean there isn't one.


Yes, that's possible IMHO. My suggestion would be:

module Enumerable
# O(1)
def empty?
each { return false }
true
end

# O(n)
def size
inject(0) {|s,| s+1}
end
end

Do you see any problems? There's only the little disadvantage that size
is O(n) while there are most likely more efficient implementations for
certain collections. But classes like Array and Hash provide their own
implementation anyway, which then overrides Enumerable#size. So there's
no drawback IMHO, only the advantage that you don't have to write it if
you have a collection that can determine its size only via a complete
iteration.

Kind regards

robert




Michael Neumann 08-10-2004 09:35 AM

Re: FirstEachLast, an extension to the Enumerable module.
 
Alexander Kellett wrote:
> On Tue, Aug 10, 2004 at 03:46:17PM +0900, Robert Klemme wrote:
>
>>Hm, sounds to me like it was not general enough to include it in
>>Enumerable. Before I see that method I'd prefer to have size and empty?
>>in Enumerable. Just my 0.02 EUR...

>
>
> personally the idea of having a method taking 4 procs
> in the stdlib is just a bit strange. i'd prefer to see
> a generic set of methods that are somehow mixedin to
> the values that a Enumerable yields, therefore allowing
> things like val.last? or first? or even a generic
> val.enum_index to replace the each_with_index rubbish.
> i've no idea how to solve this neatly unfortunately as
> extend'ing the objects that are yield'ed of course will
> have sideeffects... though most of the side effects that
> will cause problems shouldn't happen at all, e.g people
> calling is_a? a lot will have problems... i do this
> and yet i don't have an exception to such an extension...
> but this:
>
> blah.each {
> |element|
> pos = blah.index element
> puts blah[pos-1]
> puts element
> }
>
> is soooooo uggllyyy... not to mention inefficient...
> i'd just loooveeee to see a element.previous_in_enum...


Why not something like this (each_with_first_last does not exist!):

blah.each_with_first_last {|element, pos|
case pos
when :inside # or middle
...
when :first
...
when :last
...
end
}

Of course this would be somewhat slower than the approach with 4 procs,
as you have to test where you are, inside the loop. If you use the
approach above, make sure that you test for the common-case ("inside")
in the case-statement at the very beginning.

I know, you could also use each_with_index instead (this one exists!):

blah.each_with_index {|element, inx|
if inx == 0
# first
elsif inx < blah.size
# inside
else
# last
end
}

But that might not work for all Enumerable's.

Or maybe, an extended each_with_index2?:

blah.each_with_index2 {|element, inx, pos|
if pos == :first
...
}

Regards,

Michael



Michael Neumann 08-10-2004 09:43 AM

Re: FirstEachLast, an extension to the Enumerable module.
 
Michael Neumann wrote:
> I know, you could also use each_with_index instead (this one exists!):
>
> blah.each_with_index {|element, inx|
> if inx == 0
> # first
> elsif inx < blah.size


should be:

elsif inx < blah.size - 1

> # inside
> else
> # last
> end
> }
>




Robert Klemme 08-10-2004 09:46 AM

Re: FirstEachLast, an extension to the Enumerable module.
 

"Alexander Kellett" <ruby-lists@lypanov.net> schrieb im Newsbeitrag
news:20040810090629.GA13191@loki...
> On Tue, Aug 10, 2004 at 03:46:17PM +0900, Robert Klemme wrote:
> > Hm, sounds to me like it was not general enough to include it in
> > Enumerable. Before I see that method I'd prefer to have size and

empty?
> > in Enumerable. Just my 0.02 EUR...

>
> personally the idea of having a method taking 4 procs
> in the stdlib is just a bit strange.


Agreed.

> i'd prefer to see
> a generic set of methods that are somehow mixedin to
> the values that a Enumerable yields, therefore allowing
> things like val.last? or first? or even a generic
> val.enum_index to replace the each_with_index rubbish.
> i've no idea how to solve this neatly unfortunately as
> extend'ing the objects that are yield'ed of course will
> have sideeffects... though most of the side effects that
> will cause problems shouldn't happen at all, e.g people
> calling is_a? a lot will have problems...


I strongly disagree. All sorts of problems arise from this approach:

- permanent modification of elements' types
- method name collisions
- member state collisions
- thread problems (1 instance used during two parallel iterations)

The index clearly belongs to the *iteration* and not the elements.
Possible solutions:

- yield not the instance but an iteration state that has the current item
as member
- use delegator (this avoids permanent changes but has still method
collision problems)

> i do this
> and yet i don't have an exception to such an extension...
> but this:
>
> blah.each {
> |element|
> pos = blah.index element
> puts blah[pos-1]
> puts element
> }
>
> is soooooo uggllyyy... not to mention inefficient...
> i'd just loooveeee to see a element.previous_in_enum...


First of all you don't cope with the first element properly. Then, there
are simple and efficient solutions available. To name some:

# for Arrays
blah.each_with_index {
|element, pos|
puts blah[pos-1] if pos != 0
puts element
}

NOTHING = Object.new
last = NOTHING
blah.each {
|element|
puts last if NOTHING != last
puts element
last = element
}

NOTHING = Object.new
blah.inject(NOTHING) {
|last, element|
puts last if NOTHING != last
puts element
element
}

NOTHING = Object.new
blah.inject(NOTHING) {
|last, element|
process last if NOTHING != last
element
}
process last if NOTHING != last


etc. depending on what you want to do.

Regards

robert



All times are GMT. The time now is 03:52 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.