What is the best way to iterate through two containers of the same length?

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

If the two are arrays you can use Array#zip:

%w{foo bar baz}.zip([1,2,3]) {|a,b| print a, "-", b,"\n"}

foo-1
bar-2
baz-3

For the more general case you can look at Generator
http://ruby-doc.org/stdlib/libdoc/generator/rdoc/

Kind regards

robert

···

2006/3/6, Mark Watson <mark.watson@gmail.com>:

--
Have a look: Robert K. | Flickr

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

You are looking for Enumerable#zip:

>> letters = %w{A B C}
=> ["A", "B", "C"]
>> numbers = [1, 2, 3]
=> [1, 2, 3]
>> letters.zip(numbers) do |letter, number|
?> puts "#{letter}#{number}"
>> end
A1
B2
C3
=> nil

You can also use the standard generator library to turn Ruby's internal iterators into external iterators (like Java's iterators) if needed.

Hope that helps.

James Edward Gray II

···

On Mar 6, 2006, at 3:48 PM, Mark Watson wrote:

How about:

foo = ["foo","foo"]
bar = ["bar","bar"]

foo.zip(bar).each do |a,b|
  puts "#{a} #{b}"
end

Well there is zip:
irb(main):001:0> [1,2,3].zip([4,5,6]) do |a, b|
irb(main):002:1* puts "#{a} #{b}"
irb(main):003:1> end
1 4
2 5
3 6
=> nil

···

On Mar 6, 2006, at 4:48 PM, Mark Watson wrote:

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

One way I'm fond of is:
require 'generator'
enum = SyncEnumerator.new([1,2,3], [7,8,9])
enum.each do |pair|
  puts pair.inspect
end
# Results in:
[1, 7]
[2, 8]
[3, 9]

···

On 3/6/06, Mark Watson <mark.watson@gmail.com> wrote:

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

Mark Watson wrote:

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

foo = %w(x y z) ; bar = [2,4,6]
[foo, bar].transpose.each{|a,b| print a, b, $/ }
  --->
x2
y4
z6

Thanks everyone - just wht I was looking for. The SyncEnumerator class
is fine in general, and using zip is what I wanted for arrays.

Mark Watson wrote:

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

class Array
  def pairs
    first.each_with_index{|a,i|
      yield a, last[i]
    }
  end
end

[%w(x y z), [2,4,6]].pairs{|a,b| print a,b,"\n" }

Hi --

···

On Tue, 7 Mar 2006, William James wrote:

Mark Watson wrote:

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

foo = %w(x y z) ; bar = [2,4,6]
[foo, bar].transpose.each{|a,b| print a, b, $/ }
--->
x2
y4
z6

I don't think $/ is very idiomatic. See the ToDo file in the source;
it includes:

* discourage use of symbol variables (e.g. $/, etc.) in manual

:slight_smile:

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

Warning, SyncEnumerator is slow, and you probably don't need it since #zip is in enumerable.
Run the below for a demonstration. Original I had it run each benchmark 10 times by the way, but I never had the patience to let the syncenum versions finish:

% cat zip_vs_syncenum.rb
require 'benchmark'
require 'generator'
a = (1..100)
b = a.to_a.reverse

puts "Using zip:"
Benchmark.bm { |x|
   x.report {
     3.times { a.zip(b) { |x, y| z = x * y } }
   }
}
puts "Using SyncEnumerator(new every time):"
Benchmark.bm { |x|
   x.report {
     3.times {
       a_b_enum = SyncEnumerator.new(a, b)
       a_b_enum.each { |x, y| z = x * y }
     }
   }
}

puts "Using SyncEnumerator(only one created):"
Benchmark.bm { |x|
   x.report {
     a_b_enum = SyncEnumerator.new(a, b)
     3.times { a_b_enum.each { |x, y| z = x * y } }
   }
}

__END__

···

On Mar 6, 2006, at 5:17 PM, Wilson Bilkovich wrote:

One way I'm fond of is:
require 'generator'
enum = SyncEnumerator.new([1,2,3], [7,8,9])
enum.each do |pair|
  puts pair.inspect
end
# Results in:
[1, 7]
[2, 8]
[3, 9]

dblack@wobblini.net wrote:

Hi --

> Mark Watson wrote:
>> If I have two containers c1 and c2 of the same length, what is the
>> proper "Ruby way" to do this:
>>
>> c1.length.times {|i|
>> # access c1[i], c2[i]
>> }
>>
>> I like that Ruby container classes provide their own iterators, but
>> what I would like to have is something like:
>>
>> (c1,c2).each {|x1,x2| .... }
>>
>> I thought of writing my own iterator class so that I could do something
>> like:
>>
>> Iterator.new(c1,c2).each {|x1,x2| .... }
>>
>> but that looks clumsy and inefficient.
>>
>> I am transitioning to using mostly Ruby (moving away from Java, Lisp,
>> and Smalltalk) and I would like to use the proper Ruby idioms.
>
> foo = %w(x y z) ; bar = [2,4,6]
> [foo, bar].transpose.each{|a,b| print a, b, $/ }
> --->
> x2
> y4
> z6

I don't think $/ is very idiomatic. See the ToDo file in the source;
it includes:

* discourage use of symbol variables (e.g. $/, etc.) in manual

:slight_smile:

David

idiomatic, adj. Peculiar to a particular group or individual.

"\n" is found in C and in awk, but $/ isn't; so it is more
nearly peculiar to Ruby. Some may lack the capacity to remember
what it represents.

However, I have no doubt that this is an unfashionable opinion
and that your view is the dominant one.

···

On Tue, 7 Mar 2006, William James wrote:

--
idiot, n. A member of a large and powerful tribe whose influence in
human affairs has always been dominant and controlling. ... He sets
the fashions of opinion and taste, dictates the limitations of speech,
and circumscribes conduct with a dead-line.

It was recently reworked to use threads instead of continuations, this resulted in a pretty significant speed boost. I doubt it beats Enumerable#zip yet, but the speed will be nice.

James Edward Gray II

···

On Mar 6, 2006, at 5:26 PM, Logan Capaldo wrote:

Warning, SyncEnumerator is slow...

Hi --

···

On Tue, 7 Mar 2006, William James wrote:

dblack@wobblini.net wrote:

Hi --

On Tue, 7 Mar 2006, William James wrote:

Mark Watson wrote:

If I have two containers c1 and c2 of the same length, what is the
proper "Ruby way" to do this:

c1.length.times {|i|
  # access c1[i], c2[i]
}

I like that Ruby container classes provide their own iterators, but
what I would like to have is something like:

(c1,c2).each {|x1,x2| .... }

I thought of writing my own iterator class so that I could do something
like:

Iterator.new(c1,c2).each {|x1,x2| .... }

but that looks clumsy and inefficient.

I am transitioning to using mostly Ruby (moving away from Java, Lisp,
and Smalltalk) and I would like to use the proper Ruby idioms.

foo = %w(x y z) ; bar = [2,4,6]
[foo, bar].transpose.each{|a,b| print a, b, $/ }
--->
x2
y4
z6

I don't think $/ is very idiomatic. See the ToDo file in the source;
it includes:

* discourage use of symbol variables (e.g. $/, etc.) in manual

:slight_smile:

David

idiomatic, adj. Peculiar to a particular group or individual.

"\n" is found in C and in awk, but $/ isn't; so it is more
nearly peculiar to Ruby. Some may lack the capacity to remember
what it represents.

However, I have no doubt that this is an unfashionable opinion
and that your view is the dominant one.

I share your opinion that $/ is not in C or awk, but is in Ruby :slight_smile:
I'm thinking more about its position *within* Ruby, which isn't
directly connected to its presence or absence anywhere else. It's
there, but it seems to be in a bit of a shaky position.

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black