On 2002-11-16 06:07:50 +0900, dblack / candle.superlink.net wrote:
> > module Enumerable
> >
> > 	def zip(&block)
> > 		block ||= lambda { |*tuple| tuple }
> > 		size = nil
> > 		map { |x| x.size }.each do |s|
> > 			size ||= s
> > 			s == size or raise "zip with unequal length lists"
> > 		end
> > 		result = []
> > 		i = 0
> > 		catch(:stop) do
> 
> (Don't you like regular Ruby iterators? :-)

I like them, but I can't use an iterator here. I needed to get the i-th
element of every object l in the enumerable self. It would be better to
use while instead.

This solves the problem with nil elements, too. I used catch in a
previous version before I decided to first check the sizes and raise an
exception. In the previous version I wanted to stop after first reaching
the end of one list. The nil test was a stupid idea to find the end in
the first place.

> I notice that you've made this a method of Enumerable, rather than
> Array.

I just needed the each iterator, so Array would perhaps be to
restrictive. This way its possible to iterate over a tree of objects for
example if it includes Enumerable.

> What would the effect be of calling #zip on a non-Array Enumerable,
> for example a String?
> 
>   "abcde".zip   # => ?

"abcde".zip
    ==>[[97], [98], [99], [100], [101]]

The index of a string is a number. This only works because numbers
happen to have a "size" method. This nice property doesn't hold for your
example either:

[[1,2,3],[2,3,4]].zip.unzip == [[1,2,3],[2,3,4]]
    ==>true

You can get strange results if you use "\n" in a string because "each"
iterates over the lines of a string:

"abcdef\nABCDEFG".zip
    ==>[[97, 65], [98, 66], [99, 67], [100, 68], [101, 69], [102, 70], [10, 71]]

Strings aren't a good example of a collection anyway. ;) 

> (I gather from the original post that there was some discussion of
> Enumerable#zip in the Japanese list... not sure what was said,
> though, and I'm not clear on how it would work.)

BTW: It would be nice to be able to pass an arbitrary iterator to zip:

module Enumerable

	def zip(iterator = :each, &block)
		block ||= lambda { |*tuple| tuple }
		size = nil
		__send__(iterator) do |s|
			size ||= s.size
			s.size == size or raise "zip with unequal length lists"
		end
		result = []
		i = 0
		while i < size do
			tuple = []
			__send__(iterator) do |l|
				tuple << l[i]
			end
			result << block.call(*tuple)
			i += 1
		end
		result
	end

end

-- 
Poverty is an anomaly to rich people. It is very difficult to make out why 
people who want dinner do not ring the bell.
  -- Walter Bagehot