What is the best way to iterate through two containers of th


#1

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.


#2

2006/3/6, Mark Watson removed_email_address@domain.invalid:

(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


#3

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

(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 G. II


#4

How about:

foo = [“foo”,“foo”]
bar = [“bar”,“bar”]

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


#5

On 3/6/06, Mark Watson removed_email_address@domain.invalid wrote:

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

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]


#6

Mark Watson wrote:

(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


#7

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

(c1,c2).each {|x1,x2| … }
and Smalltalk) and I would like to use the proper Ruby idioms.

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


#8

Hi –

On Tue, 7 Mar 2006, William J. wrote:

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 (removed_email_address@domain.invalid)
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


#9

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


#10

Mark Watson wrote:

(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" }


#11

removed_email_address@domain.invalid wrote:

}

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.


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.


#12

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

[3, 9]
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


#13

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

Warning, SyncEnumerator is slow…

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 G. II


#14

Hi –

On Tue, 7 Mar 2006, William J. wrote:

access c1[i], c2[i]

Iterator.new(c1,c2).each {|x1,x2| … }
y4
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 (removed_email_address@domain.invalid)
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