hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

Enumerate Side-by-side with SyncEnumerator #

by why in inspect

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.

said on

Which standard library?

said on

Nevermind. Goofy mistake.

said on

Does this post refer to another blog post? Link?

said on

Oh, uh, it’s from Ruby-Talk.

said on

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!

said on

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.

said on

IIRC the patch was still using continuations, but in a somewhat different way. I don’t know if it was merged, though.

said on

Array#zip need not generate a temporary Array anymore:

  ["a", "b", "c"].zip([1, 2, 3]) do |a, b|
    puts "#{a}: #{b}" 
  end
said on

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?

said on

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

said on

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?

said on
The difference is that these continuation-based techniques are applicable in situations where #zip is not namely, when you have Enumarables you don’t want to turn into an arrays.

For example, Enumerables that yield infinite sequences, or perform costly calculations at each step, can’t be used with #zip.

said on

My Pickaxe 2ed book says that #zip is provided by Enumerable, not Array. Just FYI .

Comments are closed for this entry.