# Zip block oddities/bug?

**URL:** <https://rubytalk.org/t/zip-block-oddities-bug/10968>\
**Category:** ruby-talk\
**Created:** [12 April 2004 02:14 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968 "2004-04-12T02:14:16Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard1](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@Simon\_Strandgaard1](https://rubytalk.org/u/Simon_Strandgaard1)\
**Post date:** [12 April 2004 02:14 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/1 "2004-04-12T02:14:16Z")

</div>

When supplying a block to zip, shouldn’t you  
be able to affect the output produced by #zip ?

No matter what I do it outputs ‘nil’..

Is this the intented behavier ?

irb(main):020:0\> (4..6).zip {|i| p i; nil }  
[4]  
[5]  
[6]  
=\> nil  
irb(main):021:0\> (4..6).zip {|i| p i; }  
[4]  
[5]  
[6]  
=\> nil  
irb(main):022:0\> (4..6).zip {|i| p i; 666 }  
[4]  
[5]  
[6]  
=\> nil  
irb(main):023:0\> (4..6).zip(8) {|i| p i; 666 }  
TypeError: cannot convert Fixnum into Array  
from (irb):23:in `zip' from (irb):23 irb(main):024:0> (4..6).zip(8) {|i| p i; nil } TypeError: cannot convert Fixnum into Array from (irb):24:in `zip’  
from (irb):24  
irb(main):025:0\> (4..6).zip([8]) {|i| p i; nil }  
[4, 8]  
[5, nil]  
[6, nil]  
=\> nil  
irb(main):026:0\>

Except from the last line, I only get nil outputted  
The block is mentioned in RI, but ..

> ri Enumerable.zip  
> --------------------------------------------------------- Enumerable#zip  
> enum.zip(arg, …) =\> array  
> enum.zip(arg, …) {|arr| block } =\> nil

> **···**
>
> ## from :0 from :0
> 
> ```
> Converts any arguments to arrays, then merges elements of _enum_
> with corresponding elements from each argument. This generates a
> sequence of +enum#size+ _n_-element arrays, where _n_ is one more
> that the count of arguments. If the size of any arguemnt is less
> than +enum#size+, +nil+ values are supplied. If a block given, it
> is invoked for each output array, otherwise an array of arrays is
> returned.
> 
> a = [4, 5, 6]
> b = [7, 8, 9]
>  
> (1..3).zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
> "cat\ndog".zip([1]) #=> [["cat\n", 1], ["dog", nil]]
> (1..3).zip #=> [[1], [2], [3]]
> 
> ```
> 
> > 
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Charles\_Comstock](https://avatars.discourse-cdn.com/v4/letter/c/91b2a8/32.png) [@Charles\_Comstock](https://rubytalk.org/u/Charles_Comstock)\
**Post date:** [12 April 2004 02:39 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/2 "2004-04-12T02:39:17Z")

</div>

Simon Strandgaard wrote:

> When supplying a block to zip, shouldn’t you  
> be able to affect the output produced by #zip ?
> 
> No matter what I do it outputs ‘nil’…
> 
> Is this the intented behavier ?
> 
> irb(main):020:0\> (4…6).zip {|i| p i; nil }  
> [4]  
> [5]  
> [6]  
> =\> nil  
> irb(main):021:0\> (4…6).zip {|i| p i; }  
> [4]  
> [5]  
> [6]  
> =\> nil  
> irb(main):022:0\> (4…6).zip {|i| p i; 666 }  
> [4]  
> [5]  
> [6]  
> =\> nil  
> irb(main):023:0\> (4…6).zip(8) {|i| p i; 666 }  
> TypeError: cannot convert Fixnum into Array  
> from (irb):23:in `zip' from (irb):23 from :0 irb(main):024:0> (4..6).zip(8) {|i| p i; nil } TypeError: cannot convert Fixnum into Array from (irb):24:in `zip’  
> from (irb):24  
> from :0  
> irb(main):025:0\> (4…6).zip([8]) {|i| p i; nil }  
> [4, 8]  
> [5, nil]  
> [6, nil]  
> =\> nil  
> irb(main):026:0\>
> 
> Except from the last line, I only get nil outputted  
> The block is mentioned in RI, but …
> 
> > ri Enumerable.zip  
> > --------------------------------------------------------- Enumerable#zip  
> > enum.zip(arg, …) =\> array  
> > enum.zip(arg, …) {|arr| block } =\> nil
> 
> * * *
> 
> ```
> Converts any arguments to arrays, then merges elements of _enum_
> with corresponding elements from each argument. This generates a
> sequence of +enum#size+ _n_-element arrays, where _n_ is one more
> that the count of arguments. If the size of any arguemnt is less
> than +enum#size+, +nil+ values are supplied. If a block given, it
> is invoked for each output array, otherwise an array of arrays is
> returned.
> 
> a = [4, 5, 6]
> b = [7, 8, 9]
>  
> (1..3).zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
> "cat\ndog".zip([1]) #=> [["cat\n", 1], ["dog", nil]]
> (1..3).zip #=> [[1], [2], [3]]
> 
> ```
> 
> > 
> 
> –  
> Simon Strandgaard

irb(main):009:0\> (1…3).zip([4,5,6]) {|x| p x;}  
[1, 4]  
[2, 5]  
[3, 6]  
=\> nil

I don’t follow why it was decided that the final result be nil, it would  
be nice if returned the results from the block, meaning the above  
example would result in:

irb(main):009:0\> (1…3).zip([4,5,6]) {|x| p x; x}  
[1, 4]  
[2, 5]  
[3, 6]  
=\> [[1, 4],[2, 5], [3, 6]]

But I guess that was just the original concept.

Charles Comstock

---

<div class="post-metadata">

**Author:** ![daz](https://avatars.discourse-cdn.com/v4/letter/d/87869e/32.png) [@daz](https://rubytalk.org/u/daz)\
**Post date:** [12 April 2004 05:44 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/3 "2004-04-12T05:44:16Z")

</div>

Simon Strandgaard wrote:

> When supplying a block to zip, shouldn’t you  
> be able to affect the output produced by #zip ?

The “output” is inside the block.

> No matter what I do it outputs ‘nil’…
> 
> Is this the intented behavier ?

I hope so 😉

> irb(main):020:0\> (4…6).zip {|i| p i; nil }  
> [4]  
> [5]  
> [6]  
> =\> nil

Does what you asked. Zips 4…6 with your omitted argument  
and passes the results one at a time to the block.  
If an array was built at the same time with, say,  
(4…6000000000) you’d probably run out of memory, disk space  
for swapping and not be able to complete the operation.

Since an array is deliberately _not_ being built, what  
could usefully be returned outside the block ?  
(“nil” seems like a good choice).

daz

P.S. Swapfiles can be reset by a reboot.  
May also need a defrag, which is often a good idea.

---

<div class="post-metadata">

**Author:** ![Martin\_DeMello1](https://avatars.discourse-cdn.com/v4/letter/m/3be4f8/32.png) [@Martin\_DeMello1](https://rubytalk.org/u/Martin_DeMello1)\
**Post date:** [12 April 2004 09:24 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/4 "2004-04-12T09:24:15Z")

</div>

Think of the block zip as equivalent to ‘each’ - it iterates over the  
result set, but never actually collects it.

martin

> **···**
>
> Charles Comstock [cc1@cec.wustl.edu](mailto:cc1@cec.wustl.edu) wrote:
> 
> > irb(main):009:0\> (1…3).zip([4,5,6]) {|x| p x;}  
> > [1, 4]  
> > [2, 5]  
> > [3, 6]  
> > =\> nil
> > 
> > I don’t follow why it was decided that the final result be nil, it would  
> > be nice if returned the results from the block, meaning the above  
> > example would result in:
> > 
> > irb(main):009:0\> (1…3).zip([4,5,6]) {|x| p x; x}  
> > [1, 4]  
> > [2, 5]  
> > [3, 6]  
> > =\> [[1, 4],[2, 5], [3, 6]]

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard1](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@Simon\_Strandgaard1](https://rubytalk.org/u/Simon_Strandgaard1)\
**Post date:** [12 April 2004 13:49 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/5 "2004-04-12T13:49:14Z")

</div>

[snip]

> Since an array is deliberately _not_ being built, what  
> could usefully be returned outside the block ?  
> (“nil” seems like a good choice).

zip should simply just concatenate the data it gets back from  
the block.

I have made a pseudo-implementation, where blocks is working.  
It differs sligthly from the real zip, because I am cheating  
and using the :, rather than each.

> ruby a.rb  
> [[“a”], [“b”], [“c”]]  
> [[“a”, 1, 3, 1], [“b”, 2, 4, 1], [“c”, nil, 5, 1], [“d”, nil, 6, 0]]  
> [[4, 1, “a”], [5, 1, “b”], [nil, 0, “c”]]  
> [[0, :lo], [1, :lo], [2, :hi], [3, :hi], [4, :hi]]  
> [9, “a”, 8, “b”, 7, “c”]  
> expand -t2 a.rb  
> module Enumerable  
> def zip2(\*args)  
> res =   
> self.each\_with\_index do |element, index|  
> data = [element] + args.map{|i| i.respond\_to?(:) ? i[index] : i}  
> res += block\_given? ? yield(data) : [data]  
> end  
> res  
> end  
> end  
> p %w(a b c).zip2  
> p %w(a b c d).zip2([1, 2], [3, 4, 5, 6], 7)  
> p %w(a b c).zip2(3, [4, 5]) {|i| [i.reverse]}  
> p (0…4).zip2 {|i| [i \<\< (i[0] \< 2 ? :lo : :hi)]}  
> p %w(a b c).zip2([9, 8, 7]) {|i| i.reverse}

It wakes memories of inject.

> **···**
>
> On Mon, 12 Apr 2004 07:42:35 +0100, daz wrote:
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard1](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@Simon\_Strandgaard1](https://rubytalk.org/u/Simon_Strandgaard1)\
**Post date:** [12 April 2004 12:14 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/6 "2004-04-12T12:14:18Z")

</div>

[snip]

> > irb(main):009:0\> (1…3).zip([4,5,6]) {|x| p x; x}  
> > [1, 4]  
> > [2, 5]  
> > [3, 6]  
> > =\> [[1, 4],[2, 5], [3, 6]]

Agree, thats how 'zip’s output should be.

> Think of the block zip as equivalent to ‘each’ - it iterates over the  
> result set, but never actually collects it.

Its opfuscation to to use ‘zip as each’.

To me it looks like concatenation of block result was  
forgotten. Therefore I ask… is it intended?

IMHO The ‘each’ behavier is othogonal from ‘zip’.  
Then its better to remove the behaver completely or  
fix it. Leaving it unmodified confuses more than it helps.

😉

> **···**
>
> On Mon, 12 Apr 2004 10:20:34 +0000, Martin DeMello wrote:
> 
> > Charles Comstock [cc1@cec.wustl.edu](mailto:cc1@cec.wustl.edu) wrote:
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Martin\_DeMello1](https://avatars.discourse-cdn.com/v4/letter/m/3be4f8/32.png) [@Martin\_DeMello1](https://rubytalk.org/u/Martin_DeMello1)\
**Post date:** [12 April 2004 14:44 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/7 "2004-04-12T14:44:13Z")

</div>

Note the difference:

a.zip(b,c).map {|i| … } # builds the array, then iterates over it  
a.zip(b,c) {|i| … } # generates values one by one and calls block

If the latter functionality were not built into zip, there’d be no way  
to do it from ‘outside’, short of using a continuation. As daz points  
out, there are definitely times you’d want to iterate without building  
either an intermediate or an output array.

martin

> **···**
>
> Simon Strandgaard [neoneye@adslhome.dk](mailto:neoneye@adslhome.dk) wrote:
> 
> > To me it looks like concatenation of block result was  
> > forgotten. Therefore I ask… is it intended?
> > 
> > IMHO The ‘each’ behavier is othogonal from ‘zip’.  
> > Then its better to remove the behaver completely or  
> > fix it. Leaving it unmodified confuses more than it helps.

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard1](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@Simon\_Strandgaard1](https://rubytalk.org/u/Simon_Strandgaard1)\
**Post date:** [12 April 2004 21:39 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/8 "2004-04-12T21:39:17Z")

</div>

I think thats a broken metaphor, to do multiway each by means  
of zip.

I don’t wanna defend my idea any longer (too much resistance).  
Isn’t there any which can say something positive… or agree with  
me on this ?

Thanks for all your comments.

> **···**
>
> On Mon, 12 Apr 2004 15:40:06 +0000, Martin DeMello wrote:
> 
> > Note the difference:
> > 
> > a.zip(b,c).map {|i| … } # builds the array, then iterates over it  
> > a.zip(b,c) {|i| … } # generates values one by one and calls block
> > 
> > If the latter functionality were not built into zip, there’d be no way  
> > to do it from ‘outside’, short of using a continuation. As daz points  
> > out, there are definitely times you’d want to iterate without building  
> > either an intermediate or an output array.
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Mark\_Hubbart](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@Mark\_Hubbart](https://rubytalk.org/u/Mark_Hubbart)\
**Post date:** [12 April 2004 22:01 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/9 "2004-04-12T22:01:41Z")

</div>

I would have to agree with you on this… it doesn’t make sense to me  
that the block version doesn’t collect the output of yield.

That said, I can definitely see the benefit of having it _not_ collect  
the output. I would just tend to think that the non-collecting one  
should not have the same name as the collecting one. Perhaps:

(4…6).zip(10…12) #=\> [[4, 10], [5, 11], [6, 12]]  
(4…6).zip(10…12) {|a| a[0]\*a[1] } #=\> [40, 55, 72]

and

(4…6).zip\_each(10…12) {|a| puts a[0]\*a[1] } #=\> nil

But then this would break a lot. Even if people agree with this, I  
wouldn’t expect to see it before 2.0

–Mark

> **···**
>
> On Apr 12, 2004, at 2:39 PM, Simon Strandgaard wrote:
> 
> > On Mon, 12 Apr 2004 15:40:06 +0000, Martin DeMello wrote:
> > 
> > > Note the difference:
> > > 
> > > a.zip(b,c).map {|i| … } # builds the array, then iterates over it  
> > > a.zip(b,c) {|i| … } # generates values one by one and calls  
> > > block
> > > 
> > > If the latter functionality were not built into zip, there’d be no way  
> > > to do it from ‘outside’, short of using a continuation. As daz points  
> > > out, there are definitely times you’d want to iterate without building  
> > > either an intermediate or an output array.
> > 
> > I think thats a broken metaphor, to do multiway each by means  
> > of zip.
> > 
> > I don’t wanna defend my idea any longer (too much resistance).  
> > Isn’t there any which can say something positive… or agree with  
> > me on this ?

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard1](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@Simon\_Strandgaard1](https://rubytalk.org/u/Simon_Strandgaard1)\
**Post date:** [13 April 2004 00:44 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/10 "2004-04-13T00:44:14Z")

</div>

> > > Note the difference:
> > > 
> > > a.zip(b,c).map {|i| … } # builds the array, then iterates over it  
> > > a.zip(b,c) {|i| … } # generates values one by one and calls  
> > > block
> > > 
> > > If the latter functionality were not built into zip, there’d be no way  
> > > to do it from ‘outside’, short of using a continuation. As daz points  
> > > out, there are definitely times you’d want to iterate without building  
> > > either an intermediate or an output array.
> > 
> > I think thats a broken metaphor, to do multiway each by means  
> > of zip.
> > 
> > I don’t wanna defend my idea any longer (too much resistance).  
> > Isn’t there any which can say something positive… or agree with  
> > me on this ?
> 
> I would have to agree with you on this… it doesn’t make sense to me  
> that the block version doesn’t collect the output of yield.

Great. (I was beginning to worry if it were a silly idea of mine)

> That said, I can definitely see the benefit of having it _not_ collect  
> the output. I would just tend to think that the non-collecting one  
> should not have the same name as the collecting one. Perhaps:
> 
> (4…6).zip(10…12) #=\> [[4, 10], [5, 11], [6, 12]]  
> (4…6).zip(10…12) {|a| a[0]\*a[1] } #=\> [40, 55, 72]

or a little shorter

(4…6).zip(10…12) {|a,b| a\*b } #=\> [40, 55, 72]

> and
> 
> (4…6).zip\_each(10…12) {|a| puts a[0]\*a[1] } #=\> nil
> 
> But then this would break a lot. Even if people agree with this, I  
> wouldn’t expect to see it before 2.0

Agree… thats the reason I mentioned it, so we can break as  
much as possible in the transition from 1 to 2.

> **···**
>
> On Tue, 13 Apr 2004 08:01:41 +0900, Mark Hubbart wrote:
> 
> > On Apr 12, 2004, at 2:39 PM, Simon Strandgaard wrote:
> > 
> > > On Mon, 12 Apr 2004 15:40:06 +0000, Martin DeMello wrote:
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard1](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@Simon\_Strandgaard1](https://rubytalk.org/u/Simon_Strandgaard1)\
**Post date:** [13 April 2004 22:49 UTC](https://rubytalk.org/t/zip-block-oddities-bug/10968/11 "2004-04-13T22:49:14Z")

</div>

Just submitted a RCR about the subject… vote on it here  
[http://rcrchive.net/rcr/RCR/RCR245](http://rcrchive.net/rcr/RCR/RCR245)

> **···**
>
> –  
> Simon Strandgaard
