[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

map/collect iterating over multiple arrays/arguments

zoranlazarevic

10/6/2003 11:18:00 PM

Can I iterate over multiple arrays/collections?

It is very useful (and used in Lisp a lot) to map several lists onto
one, like map/collect but iterating over multiple collections at the
same time. For example:

foods = ['banana', 'grass', 'peanuts']
animals = ['monkey', 'gnu', 'elephant']

[animals,foods].multi_each{|x,y| puts "#{x} eats #{y}" }

money eats banana
gnu eats grass
elephant eats peanuts

[animals,foods].multi_map{|x,y| "#{x} eats #{y}" }

=> ["money eats banana", "gnu eats grass", "elephant eats peanuts"]


This is relatively simple to implement using current Ruby features,
but at the cost of either zipping all input collections in memory, or
requiring that array implements integer indexing:


foods.zip(animals).each{|x,y| puts "#{x} eats #{y}" }

or

module Enumerable
def multi_map
result = []
self[0].each_index{|i|
args = self.collect{|x| x[i]}
result << yield(*args)
}
result
end
end

I assume this can also be done by using continuation, but is there a
simpler way. Are there Iterators for enumerables, like in Java?

--Laza

Zoran Lazarevic
212.569.4011
http://www.cs.columbia...
5 Answers

Simon Strandgaard

10/7/2003 12:47:00 PM

0

On Mon, 06 Oct 2003 17:17:55 -0700, Zoran Lazarevic wrote:
> Can I iterate over multiple arrays/collections?

server> ruby dual.rb
["a", 1]
["b", 2]
["c", 3]
["d", 4]
["e", 5]
server> cat dual.rb
require 'iterator'

a = %w(a b c d e).create_iterator
b = (1..5).to_a.create_iterator
until a.is_done?
p [a.current, b.current]
a.next
b.next
end
server>


[snip]
> Are there Iterators for enumerables, like in Java?

Yes I have made some iterator classes.. But its not yet released.

You can get the 'iterator.rb' file here:
http://rubyforge.org/cgi-bin/cvsweb.cgi/projects/experimental/iterator2/iterator.rb?rev=1.1&content-type=text/x-cvsweb-markup&cvsro...



--
Simon Strandgaard





zoranlazarevic

10/8/2003 3:51:00 AM

0

Simon Strandgaard wrote in message news:...
> On Mon, 06 Oct 2003 17:17:55 -0700, Zoran Lazarevic wrote:
> > Can I iterate over multiple arrays/collections?
> > Are there Iterators for enumerables, like in Java?
>
> Yes I have made some iterator classes.. But its not yet released.
>

Simon, the iterator class uses indexing ( @data[@position] ) and that
is exactly what I tried to avoid. This does NOT work for collections
that do not support indexing operator[] (e.g. linked lists, iterating
through SQL resultset, etc.)

Apparently it is not possible to iterate using Collection.each over
multiple collections. It is possible by using one thread per
collection, but I do not want to go there.

--Laza

Melanie Fielder

10/8/2003 7:10:00 AM

0

Zoran Lazarevic <zoranlazarevic@yahoo.com> skrev i en
nyhedsmeddelelse:32c0bb6a.0310071950.55c75dd0@posting.google.com...
> Simon Strandgaard wrote in message news:...
> > On Mon, 06 Oct 2003 17:17:55 -0700, Zoran Lazarevic wrote:
> > > Can I iterate over multiple arrays/collections?
> > > Are there Iterators for enumerables, like in Java?
> >
> > Yes I have made some iterator classes.. But its not yet released.
> >
>
> Simon, the iterator class uses indexing ( @data[@position] ) and that
> is exactly what I tried to avoid. This does NOT work for collections
> that do not support indexing operator[] (e.g. linked lists, iterating
> through SQL resultset, etc.)

You can write an implicit iterator, like this:

server> cat snippet_implicit.rb
require 'iterator'
class ImplicitIterator < Iterator::Base
def initialize
super()
first
end
def first; @value = 0 end
def next; @value += 1 end
def is_done?; @value >= 10 end
def current; @value end
end
i = ImplicitIterator.new
until i.is_done?
p i.current
i.next
end
server> ruby snippet_implicit.rb
0
1
2
3
4
5
6
7
8
9
server>

Is this better ? :-)


> Apparently it is not possible to iterate using Collection.each over
> multiple collections. It is possible by using one thread per
> collection, but I do not want to go there.

You can make an iterator which can iterate over multiple iterators at
the same time, like this:

require 'iterator'
class MultiIterator < Iterator::Base
def initialize(*iterators)
@iterators = iterators
first
end
def first; @iterators.each{|i| i.first} end
def next; @iterators.each{|i| i.next} end
def is_done?
@iterators.each{|i| return true if i.is_done? }
false
end
def current; @iterators end
end

a = %w(a b c d e).create_iterator
b = (0..4).to_a.create_iterator
i = MultiIterator.new(a, b)
until i.is_done?
ia, ib = i.current
p [ia.current, ib.current]
i.next
end

Is this better ? ... I hope ;-)


--
Simon Strandgaard




quent

10/8/2003 4:11:00 PM

0

zoranlazarevic@yahoo.com (Zoran Lazarevic) wrote in message news:<32c0bb6a.0310071950.55c75dd0@posting.google.com>...

> Apparently it is not possible to iterate using Collection.each over
> multiple collections. It is possible by using one thread per
> collection, but I do not want to go there.

a continuations multi_each has been placed on the wiki at rubygarden.org
if you are interested

ahoward

10/8/2003 4:31:00 PM

0