Implementing the "each" method for own classes

(Philipp Huber) #1

hello!

first of all, i'm new to ruby and this list.

my question is, i have a class "Queue" which implements a queue as
linked list of "Item" objects. i'd like to implement an each method,
so i can do something like

queue.each do |item|
   item.do_somethng
end

any help would be appreciated!
thanks,
philipp

(Brian Schröder) #2

It is a bit hard to help you, if we don't know your classes. But lets
say you have a class
class QueueNode
  attr_accessor :next
  ...
end

and a class Queue with a variable @root holding the first entry of the
queue you could implement each as

class Queue
  ...

  def each(&block)
    node = @root
    begin
      block[node]
    end while node = node.next
  end
end

or you could use yield
  
class Queue
  ...

  def each
    node = @root
    begin
      yield node
    end while node = node.next
  end
end

that depends on personal preference.

hope to help,

Brian

···

On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:

hello!

first of all, i'm new to ruby and this list.

my question is, i have a class "Queue" which implements a queue as
linked list of "Item" objects. i'd like to implement an each method,
so i can do something like

queue.each do |item|
   item.do_somethng
end

any help would be appreciated!
thanks,
philipp

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

(Brian Schröder) #3

Just one more hint in case you didn't know it. You should do

class Queue
  include Enumerable
  ...
end

to get all the nice Enumerable methods for free.
     all?, any?, collect, detect, each_with_index, entries, find,
     find_all, grep, include?, inject, map, max, member?, min,
     partition, reject, select, sort, sort_by, to_a, to_set, zip

regards,

Brian

···

On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:

hello!

first of all, i'm new to ruby and this list.

my question is, i have a class "Queue" which implements a queue as
linked list of "Item" objects. i'd like to implement an each method,
so i can do something like

queue.each do |item|
   item.do_somethng
end

any help would be appreciated!
thanks,
philipp

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

(Philipp Huber) #4

thanks a lot, works exactly as i wanted :slight_smile:

···

On 9/1/05, Brian Schröder <ruby.brian@gmail.com> wrote:

On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:
> hello!
>
> first of all, i'm new to ruby and this list.
>
> my question is, i have a class "Queue" which implements a queue as
> linked list of "Item" objects. i'd like to implement an each method,
> so i can do something like
>
> queue.each do |item|
> item.do_somethng
> end
>
> any help would be appreciated!
> thanks,
> philipp
>
>

It is a bit hard to help you, if we don't know your classes. But lets
say you have a class
class QueueNode
  attr_accessor :next
  ...
end

and a class Queue with a variable @root holding the first entry of the
queue you could implement each as

class Queue
  ...

  def each(&block)
    node = @root
    begin
      block[node]
    end while node = node.next
  end
end

or you could use yield

class Queue
  ...

  def each
    node = @root
    begin
      yield node
    end while node = node.next
  end
end

that depends on personal preference.

hope to help,

Brian
--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

(Robert) #5

Philipp Huber wrote:

thanks a lot, works exactly as i wanted :slight_smile:

Two remarks:

- did you test this with an empty queue (I guess in that case @root will
be empty so you'll likely need something like

n = @root
while n
  yield n.element
  n = n.next
end

- by convention #each returns self which wasn't show in Brian's example.

Kind regards

    robert

(Philipp Huber) #6

actually i did test it with a queue filled with a few elements. as you
said the condition for the while loop should be testet at the
beginning, otherwise nil could be returned.
so my code looks like this:

def each
  node=@head
  while node=node.next
   yield node.content
  end
end

do you have an example for the second remark, as i don't quite
understand what you mean

thanks,
philipp

(Brian Schröder) #7

Sorry for posting something that untested. But as I look again you
continue to have bugs in your code.

You are missing the first element. The following should work and also
return self. That allows you to do something like the following:

queue.each do | element | element.seen += 1 end.each do | element |
puts element end

Beware that the above example does not make that much sense, but I do
not have a better example ready.

def each
  node=@head
  while node
    yield node.content
    node=node.next
  end
  self
end

hope to help

Brian

···

On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:

actually i did test it with a queue filled with a few elements. as you
said the condition for the while loop should be testet at the
beginning, otherwise nil could be returned.
so my code looks like this:

def each
  node=@head
  while node=node.next
   yield node.content
  end
end

do you have an example for the second remark, as i don't quite
understand what you mean

thanks,
philipp

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

(Philipp Huber) #8

of course your right, my variant leaves out the first element.
what's actually the sense behind returning self?

···

On 9/1/05, Brian Schröder <ruby.brian@gmail.com> wrote:

On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:
> actually i did test it with a queue filled with a few elements. as you
> said the condition for the while loop should be testet at the
> beginning, otherwise nil could be returned.
> so my code looks like this:
>
> def each
> node=@head
> while node=node.next
> yield node.content
> end
> end
>
> do you have an example for the second remark, as i don't quite
> understand what you mean
>
> thanks,
> philipp
>
>

Sorry for posting something that untested. But as I look again you
continue to have bugs in your code.

You are missing the first element. The following should work and also
return self. That allows you to do something like the following:

queue.each do | element | element.seen += 1 end.each do | element |
puts element end

Beware that the above example does not make that much sense, but I do
not have a better example ready.

def each
  node=@head
  while node
    yield node.content
    node=node.next
  end
  self
end

hope to help

Brian

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

(Robert) #9

Brian Schröder wrote:

actually i did test it with a queue filled with a few elements. as
you said the condition for the while loop should be testet at the
beginning, otherwise nil could be returned.
so my code looks like this:

def each
  node=@head
  while node=node.next
   yield node.content
  end
end

do you have an example for the second remark, as i don't quite
understand what you mean

Just put "return self" or just "self" in the last line of your method
#each.

Sorry for posting something that untested. But as I look again you
continue to have bugs in your code.

You are missing the first element. The following should work and also
return self. That allows you to do something like the following:

That's only true if head is nil for an empty queue. There are
implementations out there (for example java.util.LinkedList) where the
first element is never null. It might be though that it makes sense only
for a doubly linked list.

queue.each do | element | element.seen += 1 end.each do | element |
puts element end

Beware that the above example does not make that much sense, but I do
not have a better example ready.

def each
  node=@head
  while node
    yield node.content
    node=node.next
  end
  self
end

That's what I suggested, isn't it?

Kind regards

    robert

···

On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:

(Robert) #10

Philipp Huber wrote:

of course your right, my variant leaves out the first element.
what's actually the sense behind returning self?

Don't ask. There's a dark secret connected to this. Noone ever lived to
tell. Many have tried to provide explanations (such as support of method
chaining) but the truth was never revealed...

:wink:

Cheers

    robert

(Brian Schröder) #11

Brian Schröder wrote:
>> actually i did test it with a queue filled with a few elements. as
>> you said the condition for the while loop should be testet at the
>> beginning, otherwise nil could be returned.
>> so my code looks like this:
>>
>> def each
>> node=@head
>> while node=node.next
>> yield node.content
>> end
>> end
>>
>> do you have an example for the second remark, as i don't quite
>> understand what you mean

Just put "return self" or just "self" in the last line of your method
#each.

> Sorry for posting something that untested. But as I look again you
> continue to have bugs in your code.
>
> You are missing the first element. The following should work and also
> return self. That allows you to do something like the following:

That's only true if head is nil for an empty queue. There are
implementations out there (for example java.util.LinkedList) where the
first element is never null. It might be though that it makes sense only
for a doubly linked list.

> queue.each do | element | element.seen += 1 end.each do | element |
> puts element end
>
> Beware that the above example does not make that much sense, but I do
> not have a better example ready.
>
> def each
> node=@head
> while node
> yield node.content
> node=node.next
> end
> self
> end

That's what I suggested, isn't it?

It is - I'm sorry, I'm task-switching in my mind too fast at the
moment. I will concentrate on my thesis now ...

best regards,

Brian

···

On 01/09/05, Robert Klemme <bob.news@gmx.net> wrote:

> On 01/09/05, Philipp Huber <huber.philipp@gmail.com> wrote:

Kind regards

    robert

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

(Daryl Richter) #12

Robert Klemme wrote:

Philipp Huber wrote:

of course your right, my variant leaves out the first element.
what's actually the sense behind returning self?

Don't ask. There's a dark secret connected to this. Noone ever lived to
tell. Many have tried to provide explanations (such as support of method
chaining) but the truth was never revealed...

Chaining is the reason.

a.please.do.this

instead of:

a.please
a.do
a.this

···

:wink:

Cheers

    robert

--
Daryl Richter
Platform Author & Director of Technology

(( Brandywine Asset Management )
  ( "Expanding the Science of Global Investing" )
  ( http://www.brandywine.com ))