zip block oddities/bug?

S

Simon Strandgaard

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


erver> 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]]

server>
 
C

Charles Comstock

Simon said:
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 ..


erver> 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]]

server>

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
 
D

daz

Simon said:
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.
 
M

Martin DeMello

Charles Comstock said:
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]]

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

martin
 
S

Simon Strandgaard

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.

;-)
 
S

Simon Strandgaard

On Mon, 12 Apr 2004 07:42:35 +0100, daz wrote:
[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.

server> 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"]
server> 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}
server>

It wakes memories of inject.
 
M

Martin DeMello

Simon Strandgaard said:
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.

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
 
S

Simon Strandgaard

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 ?

Thanks for all your comments.
 
M

Mark Hubbart

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.

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
 
S

Simon Strandgaard

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top