[ann] iterator-0.7

  • Thread starter Simon Strandgaard
  • Start date
S

Simon Strandgaard

homepage:
http://raa.ruby-lang.org/list.rhtml?name=iterator

download:
http://rubyforge.org/frs/?group_id=18&release_id=467


External iterators with some STL inspiration.


#
# example of how to do multiway each
#
require 'iterator'
data_a = %w(a b c d)
data_b = (0..3)
ia = Iterator::Continuation.new(data_a, :each)
ib = Iterator::Continuation.new(data_b, :each)
result = []
while ia.has_next? and ib.has_next?
result << ia.current
result << ib.current
ia.next
ib.next
end
ia.close
ib.close
p result # ["a", 0, "b", 1, "c", 2, "d", 3]




#
# example of how to concat iterators
#
require 'iterator'
ary1 = "Hell".split(//).to_a
ary2 = "O wO".split(//).to_a
ary3 = "rld!".split(//).to_a
i1 = ary1.create_iterator
i2 = ary2.create_iterator
i3 = ary3.create_iterator
iterator = Iterator::Concat.new([i1, i2, i3])
ary2.map!{|i|i.swapcase}
puts iterator.to_a.join #-> Hello World!
 
R

Robert Klemme

Simon Strandgaard said:
homepage:
http://raa.ruby-lang.org/list.rhtml?name=iterator

download:
http://rubyforge.org/frs/?group_id=18&release_id=467


External iterators with some STL inspiration.


#
# example of how to do multiway each
#
require 'iterator'
data_a = %w(a b c d)
data_b = (0..3)
ia = Iterator::Continuation.new(data_a, :each)
ib = Iterator::Continuation.new(data_b, :each)
result = []
while ia.has_next? and ib.has_next?
result << ia.current
result << ib.current
ia.next
ib.next
end
ia.close
ib.close
p result # ["a", 0, "b", 1, "c", 2, "d", 3]




#
# example of how to concat iterators
#
require 'iterator'
ary1 = "Hell".split(//).to_a
ary2 = "O wO".split(//).to_a
ary3 = "rld!".split(//).to_a
i1 = ary1.create_iterator
i2 = ary2.create_iterator
i3 = ary3.create_iterator
iterator = Iterator::Concat.new([i1, i2, i3])
ary2.map!{|i|i.swapcase}
puts iterator.to_a.join #-> Hello World!

Great! This looks good. I'd just do some small interface changes.

Move Array#create_iterator to Enumerable and rename it to
Enumerable#iterator (we're lazy typers) if possible. Alternatively you
could provide this wrapper:

module Enumerable
def iterator; Iterator::Continuation.new(self, :each); end
end

Make Iterator::Concat#initialize to be able to do
iterator = Iterator::Concat.new(i1, i2, i3) # brackets removed
iterator = Iterator::Concat.new(i1, ary2, i3)

Nice to have but maybe not worth the effort:
Iterator#reset

Regards

robert
 
M

Michael Neumann


BTW, enumerator and generator both serve similar puposes and ship with
Ruby by default.

require 'enumerator'
require 'generator'

si = "string".to_enum:)each_byte)

for byte in si
...
end


g = Generator.new(si)
while g.next?
p g.next
end

I am not sure where the differences are. And I don't say that iterator
is not useful ;-)

Regards,

Michael
 
S

Simon Strandgaard

Michael Neumann said:

BTW, enumerator and generator both serve similar puposes and ship with
Ruby by default. [snip]
I am not sure where the differences are. And I don't say that iterator
is not useful ;-)


Yes they can do somewhat the same, I just needed some iterators customized
for my regexp engine. In paticular I needed to be able to reverse the
direction of an iterator, so that I could do lookbehind.. for instance:

irb(main):001:0> require 'iterator'
=> true
irb(main):002:0> i = %w(a b c d e).create_iterator_end.reverse
=> #<Iterator::Reverse:0x8196d3c @i=#<Iterator::Collection:0x8196df0 @data=["a", "b", "c", "d", "e"], @position=5>>
irb(main):003:0> i.to_a
=> ["e", "d", "c", "b", "a"]
irb(main):004:0>

There are probably other differences.
 
S

Simon Strandgaard

Robert Klemme said:
Simon Strandgaard said:
[snip]
Great! This looks good. I'd just do some small interface changes.

I am always open to suggestions ;-)

Move Array#create_iterator to Enumerable and rename it to
Enumerable#iterator (we're lazy typers) if possible.

Good suggestion.. will change it.

Alternatively you could provide this wrapper:

module Enumerable
def iterator; Iterator::Continuation.new(self, :each); end
end

Also a good suggestion.. will change it.


Make Iterator::Concat#initialize to be able to do
iterator = Iterator::Concat.new(i1, i2, i3) # brackets removed
iterator = Iterator::Concat.new(i1, ary2, i3)

Major dillema, I don't know how to do it.
My current Concat#initialize looks like "def initialize(iterators, position=nil)"

If I do "def initialize(*iterators, position=nil)".. that won't work ?

irb(main):001:0> def m(*args, x=nil)
irb(main):002:1> p args
irb(main):003:1> p x
irb(main):004:1> end
SyntaxError: compile error
(irb):1: syntax error
def m(*args, x=nil)
^
(irb):1: syntax error
from (irb):1
irb(main):005:0>

Any hints on how to pass 'position' to initialize ?


Nice to have but maybe not worth the effort:
Iterator#reset

Its already there.. #first and #last both resets the iterator.



Thanks for these great suggestions.. keep them coming.
 
R

Robert Klemme

Simon Strandgaard said:
Robert Klemme said:
Simon Strandgaard said:
[snip]
Great! This looks good. I'd just do some small interface changes.

I am always open to suggestions ;-)

Move Array#create_iterator to Enumerable and rename it to
Enumerable#iterator (we're lazy typers) if possible.

Good suggestion.. will change it.

Alternatively you could provide this wrapper:

module Enumerable
def iterator; Iterator::Continuation.new(self, :each); end
end

Also a good suggestion.. will change it.


Make Iterator::Concat#initialize to be able to do
iterator = Iterator::Concat.new(i1, i2, i3) # brackets removed
iterator = Iterator::Concat.new(i1, ary2, i3)

Major dillema, I don't know how to do it.
My current Concat#initialize looks like "def initialize(iterators,
position=nil)"

Ah, I see.
If I do "def initialize(*iterators, position=nil)".. that won't work ?

irb(main):001:0> def m(*args, x=nil)
irb(main):002:1> p args
irb(main):003:1> p x
irb(main):004:1> end
SyntaxError: compile error
(irb):1: syntax error
def m(*args, x=nil)
^
(irb):1: syntax error
from (irb):1
irb(main):005:0>

Any hints on how to pass 'position' to initialize ?

def init(*args)
if Numeric === args[-1]
pos = args[-1]
args.slice!(-1, 1)
else
pos = nil
end

puts "iterators: #{args.inspect}"
puts "position : #{pos.inspect}"
end

irb(main):066:0> init "a","s",1
iterators: ["a", "s"]
position : 1
=> nil
irb(main):067:0> init "a","s"
iterators: ["a", "s"]
position : nil
=> nil
irb(main):068:0> init
iterators: []
position : nil
=> nil

Or even

def init2(*args)
pos = nil
iters = []

args.each do |arg|
case arg
when Numeric
raise ArgumentError, "duplicate start positions" if pos
pos = arg
when Iterator # place appropriate type(s) here
iters << arg
when Enumerable
iters << Iterator::Continuation.new(arg, :each)
else
raise ArgumentError, "Don't know what to do with #{arg.inspect}"
end
end

puts "iterators: #{iters.inspect}"
puts "position : #{pos.inspect}"
end

Its already there.. #first and #last both resets the iterator.

Ooops, overlooked that one.
Thanks for these great suggestions.. keep them coming.

You're welcome.

Kind regards

robert
 
S

Sascha Doerdelmann

Simon Strandgaard said:
External iterators with some STL inspiration.

Just in case you didn't know.

There's another iterator module availiable as part of the ruby graph
library
http://raa.ruby-lang.org/list.rhtml?name=RGL
http://rgl.sourceforge.net/classes/Stream.html

I think it's iterators are called streams because they are inspired by
a Smalltalk class "Stream". Graph algorithms can be build as streams
so there's some STL and boost flavour in these modules, too.

Cheers
Sascha
 
S

Simon Strandgaard

Just in case you didn't know.

There's another iterator module availiable as part of the ruby graph
library
http://raa.ruby-lang.org/list.rhtml?name=RGL
http://rgl.sourceforge.net/classes/Stream.html

I think it's iterators are called streams because they are inspired by
a Smalltalk class "Stream". Graph algorithms can be build as streams
so there's some STL and boost flavour in these modules, too.

Actually I started out with that library for my regexp engine, but there were
just too many weird things going on (read: bugs). The Stream library is
poorly unittested. Sorry.
 
S

Simon Strandgaard

Robert Klemme said:
Simon Strandgaard said:
Major dillema, I don't know how to do it.
My current Concat#initialize looks like "def initialize(iterators,
position=nil)"

Ah, I see.
If I do "def initialize(*iterators, position=nil)".. that won't work ?

irb(main):001:0> def m(*args, x=nil)
irb(main):002:1> p args
irb(main):003:1> p x
irb(main):004:1> end
SyntaxError: compile error
(irb):1: syntax error
def m(*args, x=nil)
^
(irb):1: syntax error
from (irb):1
irb(main):005:0>

Any hints on how to pass 'position' to initialize ?

def init(*args)
if Numeric === args[-1]
pos = args[-1]
args.slice!(-1, 1)
else
pos = nil
end

puts "iterators: #{args.inspect}"
puts "position : #{pos.inspect}"
end

Hmmm.. maybe we are trying to put too much logic into
the initialize method. We could make a factory method for that.

class Concat
def self.mk(*iterators); end
end



irb(main):066:0> init "a","s",1
iterators: ["a", "s"]
position : 1
=> nil
irb(main):067:0> init "a","s"
iterators: ["a", "s"]
position : nil
=> nil
irb(main):068:0> init
iterators: []
position : nil
=> nil

Or even

def init2(*args)
pos = nil
iters = []

args.each do |arg|
case arg
when Numeric
raise ArgumentError, "duplicate start positions" if pos
pos = arg
when Iterator # place appropriate type(s) here
iters << arg
when Enumerable
iters << Iterator::Continuation.new(arg, :each)
else
raise ArgumentError, "Don't know what to do with #{arg.inspect}"
end
end

puts "iterators: #{iters.inspect}"
puts "position : #{pos.inspect}"
end

Bigger is better.. the factory method approach is visually better.


Interesting dillema though :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,112
Latest member
VinayKumar Nevatia
Top