# Map/collect iterating over multiple arrays/arguments

**URL:** <https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435>\
**Category:** ruby-talk\
**Created:** [6 October 2003 23:23 UTC](https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435 "2003-10-06T23:23:13Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Zoranlazarevic](https://avatars.discourse-cdn.com/v4/letter/z/f04885/32.png) [@Zoranlazarevic](https://rubytalk.org/u/Zoranlazarevic)\
**Post date:** [6 October 2003 23:23 UTC](https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435/1 "2003-10-06T23:23:13Z")

</div>

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.edu/~laza](http://www.cs.columbia.edu/~laza)

---

<div class="post-metadata">

**Author:** ![Zoranlazarevic](https://avatars.discourse-cdn.com/v4/letter/z/f04885/32.png) [@Zoranlazarevic](https://rubytalk.org/u/Zoranlazarevic)\
**Post date:** [8 October 2003 04:07 UTC](https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435/2 "2003-10-08T04:07:36Z")

</div>

Simon Strandgaard wrote in message news:…

> > 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

> **···**
>
> > On Mon, 06 Oct 2003 17:17:55 -0700, Zoran Lazarevic wrote:

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard3](https://avatars.discourse-cdn.com/v4/letter/s/f17d59/32.png) [@Simon\_Strandgaard3](https://rubytalk.org/u/Simon_Strandgaard3)\
**Post date:** [8 October 2003 07:27 UTC](https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435/3 "2003-10-08T07:27:58Z")

</div>

Zoran Lazarevic [zoranlazarevic@yahoo.com](mailto:zoranlazarevic@yahoo.com) skrev i en  
[nyhedsmeddelelse:32c0bb6a.0310071950.55c75dd0@posting.google.com](mailto:nyhedsmeddelelse:32c0bb6a.0310071950.55c75dd0@posting.google.com)…

> Simon Strandgaard wrote in message news:…
> 
> > > 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:

> 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  
> ruby snippet\_implicit.rb  
> 0  
> 1  
> 2  
> 3  
> 4  
> 5  
> 6  
> 7  
> 8  
> 9

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 😉

> **···**
>
> > > On Mon, 06 Oct 2003 17:17:55 -0700, Zoran Lazarevic wrote:
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Quent](https://avatars.discourse-cdn.com/v4/letter/q/e19adc/32.png) [@Quent](https://rubytalk.org/u/Quent)\
**Post date:** [8 October 2003 16:29 UTC](https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435/4 "2003-10-08T16:29:32Z")

</div>

[zoranlazarevic@yahoo.com](mailto:zoranlazarevic@yahoo.com) (Zoran Lazarevic) wrote in message news:[32c0bb6a.0310071950.55c75dd0@posting.google.com](mailto: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](http://rubygarden.org)  
if you are interested

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard1](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@Ara.T.Howard1](https://rubytalk.org/u/Ara.T.Howard1)\
**Post date:** [8 October 2003 17:49 UTC](https://rubytalk.org/t/map-collect-iterating-over-multiple-arrays-arguments/8435/5 "2003-10-08T17:49:42Z")

</div>

heres another one. it also defines an iterator class:

----CUT----  
module Enumerable  
class Iterator  
public

```
attr_reader :enumerable, :has_next

def initialize enumerable, end_value = nil, &end_block
  @enumerable = enumerable
  @end_value = end_value
  @end_block = end_block
  initialize_fetch_block
end

def next
  @has_next ? fetch_next_element : fetch_end_value
end

def rewind
  initialize_fetch_block
  self
end

```

protected

```
def initialize_fetch_block
  callcc do |@after_fetch|
@has_next = true
@enumerable.each do |@next_element|
  callcc do |@next_fetch| @after_fetch.call end
end
@has_next = false
@next_fetch = nil
@after_fetch.call
  end
  @after_fetch = nil
end

def fetch_next_element
  result = @next_element
  callcc do |@after_fetch| @next_fetch.call end
  @after_fetch = nil
  result
end

def fetch_end_value
  @end_block ? @end_block.call : @end_value
end

```

end

# enumerable instance methods

def iterator; @iterator = Iterator.new self; end

# enumerables class methods

class \<\< self  
def each(\*enumerables, &block)  
iterators = enumerables.collect{|e| e.iterator}  
while true  
args = iterators.collect{|i| i.next}  
if args.detect{|arg| arg}  
block.call \*args  
else  
return enumerables  
end  
end  
end  
def collect(\*enumerables, &block)  
ret =   
each(\*enumerables){|\*args| ret \<\< (block.call \*args)}  
ret  
end  
alias map collect  
end  
end

if $0 == **FILE**  
a = [‘fee’,‘fie’,‘foe’,‘fum’]  
h = {‘k’ =\> ‘v’, ‘K’ =\> ‘V’}

ai = a.iterator  
hi = h.iterator

while ((n = ai.next)) do  
puts n.inspect  
end

while ((n = hi.next)) do  
puts n.inspect  
end

Enumerable::each a, h do |elem, kv|  
puts elem.inspect  
puts kv.inspect  
end

p Enumerable::collect(a,h){|e,kv| [e,kv]}  
end

**END**

OUTPUT:

“fee”  
“fie”  
“foe”  
“fum”  
[“K”, “V”]  
[“k”, “v”]  
“fee”  
[“K”, “V”]  
“fie”  
[“k”, “v”]  
“foe”  
nil  
“fum”  
nil  
[[“fee”, [“K”, “V”]], [“fie”, [“k”, “v”]], [“foe”, nil], [“fum”, nil]]  
----CUT----

-a

> **···**
>
> On Wed, 8 Oct 2003, quent wrote:
> 
> > [zoranlazarevic@yahoo.com](mailto:zoranlazarevic@yahoo.com) (Zoran Lazarevic) wrote in message news:[32c0bb6a.0310071950.55c75dd0@posting.google.com](mailto: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](http://rubygarden.org)  
> > if you are interested
> 
> ====================================
> 
> > Ara Howard  
> > NOAA Forecast Systems Laboratory  
> > Information and Technology Services  
> > Data Systems Group  
> > R/FST 325 Broadway  
> > Boulder, CO 80305-3328  
> > Email: [ara.t.howard@noaa.gov](mailto:ara.t.howard@noaa.gov)  
> > Phone: 303-497-7238  
> > Fax: 303-497-7259  
> > The difference between art and science is that science is what we understand  
> > well enough to explain to a computer. Art is everything else.  
> > – Donald Knuth, “Discover”  
> > ~ \> /bin/sh -c ‘for lang in ruby perl; do $lang -e “print "\x3a\x2d\x29\x0a"”; done’  
> > ====================================
