Enumerate Side-by-side with SyncEnumerator #
Kenneth Kunz shined a light on the SyncEnumerator
class, which comes with the standard library. A little bit of slightly life-changing code I’d say.
require 'generator' numbers = (1..5) letters = ('a'..'c') enum = SyncEnumerator.new( numbers, letters ) enum.each { |num, let| print "#{num},#{let} " }
Which prints: 1,a 2,b 3,c 4, 5,
.
The each
iterates through both collections simultaneously. You can pass any number of collections into SyncEnumerator
. And, naturally, you can use any of the normal set of Enumerable
methods. And you will.
require 'generator' class Sync < SyncEnumerator def self.[]( *args ); new( *args ); end end Sync[numbers,letters].map { |n,l| "#{n} #{l}" }.join "\n"
Update: You should definitely read the comments, noting the speed impairment incurred by using this generator, when compared to an equivalent technique starring Array#zip
.
batkins
Which standard library?
batkins
Nevermind. Goofy mistake.
Michael
Does this post refer to another blog post? Link?
why
Oh, uh, it’s from Ruby-Talk.
emmanuel
I used it in the past, but it was dreadfully slow, because it used continuations. Maybe it changed now. At that time, i replaced my call with Array#zip which was an immediate performance boost. I saw once on ruby-talk someone offering a patch converting it to work without continuations but I don’t know if it was merged. Even if it was, beware, this can be mighty slow in some older rubys!
bitserf
Emmanuel, I’m afraid its still slow. I’ve also personally switched to #zip, the cost of creating the temporary arrays seems to be less than using SyncEnumerator.
gab
IIRC the patch was still using continuations, but in a somewhat different way. I don’t know if it was merged, though.
flgr
Array#zip need not generate a temporary Array anymore:
Gene
what is the syntax that lets you control whether to truncate longer input sequences, or pad shorter sequences (sorta like the difference betw zip(list1,list2) and map(None,list1,list2) in python?
emmanuel
ok, if the speed problem is still there, just to expand on it.
we are talking two orders of magnitude slower than Array#zip, minutes instead of split-seconds (at least in the cases where i tried). In my case maybe it got worse because my machine trashed (several hundreds of megs taken by ruby).
I posted on it there: http://www.ruby-talk.org/cgi-bin/vframe.rb/ruby/ruby-talk/105936?105721-106925+split-mode-vertical
ken
OK, point taken… I hereby rescind my Ruby-Talk post, and I will dutifully zip from this day forward (my wife will be glad to hear this).
Unless I am working with arbitrary (non-Array) Enumerable collections and speed is not a consideration, in which case I may slip-in an occasional SyncEnumerator just for nostalgia.
Perhaps Rite (YARV) will address the performance problems?
William
For example, Enumerables that yield infinite sequences, or perform costly calculations at each step, can’t be used with #zip.
Joe
My Pickaxe 2ed book says that #zip is provided by Enumerable, not Array. Just FYI .
Comments are closed for this entry.