Proposal - zip to do padding

We already have pad with nils

irb(main):001:0> (4…6).zip(nil)
=> [[4, nil], [5, nil], [6, nil]]

It would be awesome if #zip could do the same
with non-nil elements… (this is what I propose)

p (4…6).zip(‘a’)
#=> [[4, “a”], [5, “a”], [6, “a”]]
p (4…6).zip(‘a’, ‘b’)
#=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]

However this is not the way it works at the moment,
so that behavier would need to be abandoned.
Which I consider weird and restrictive… agree?

irb(main):002:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, nil], [6, nil]]
irb(main):003:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, nil, nil], [6, nil, nil]]

#zip behaves nice when you pass it an Array.

irb(main):004:0> (4…6).zip([‘a’, ‘b’])
=> [[4, “a”], [5, “b”], [6, nil]]
irb(main):005:0>

BTW: (4…6).zip #=> [[4], [5], [6]]
Cool :wink:

···


Simon Strandgaard

Simon Strandgaard wrote:

It would be awesome if #zip could do the same
with non-nil elements… (this is what I propose)

p (4…6).zip(‘a’, ‘b’)
#=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]

p (4…6).map {|n| [n, ‘a’, ‘b’]}

#=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]

Consider: Is there a better tool for the job
before looking for YetAnotherRCR.

daz

We already have pad with nils

irb(main):001:0> (4…6).zip(nil)
=> [[4, nil], [5, nil], [6, nil]]

note that this doesn’t work in the current version:

irb(main):001:0> RUBY_VERSION
=> “1.9.0”
irb(main):002:0> (4…6).zip(nil)
TypeError: cannot convert nil into Array
from (irb):2:in `zip’
from (irb):2

It would be awesome if #zip could do the same
with non-nil elements… (this is what I propose)

p (4…6).zip(‘a’)
#=> [[4, “a”], [5, “a”], [6, “a”]]
p (4…6).zip(‘a’, ‘b’)
#=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]

However this is not the way it works at the moment,
so that behavier would need to be abandoned.
Which I consider weird and restrictive… agree?

irb(main):002:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, nil], [6, nil]]
irb(main):003:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, nil, nil], [6, nil, nil]]

Maybe are missing the point of what zip does… when you call #zip, it
ensures the object you pass to it is an array; then it zips it. I’m
guessing #zip calls to_a on it…

But I may be misunderstanding your proposal… Isn’t what you are
proposing something like this?

irb(main):003:0> (4…6).map{|i|[i,‘a’]}
=> [[4, “a”], [5, “a”], [6, “a”]]

(as was suggested by daz elsewhere in the thread)

–Mark

···

On Apr 11, 2004, at 6:59 PM, Simon Strandgaard wrote:

#zip behaves nice when you pass it an Array.

irb(main):004:0> (4…6).zip([‘a’, ‘b’])
=> [[4, “a”], [5, “b”], [6, nil]]
irb(main):005:0>

BTW: (4…6).zip #=> [[4], [5], [6]]
Cool :wink:


Simon Strandgaard

We already have pad with nils

irb(main):001:0> (4…6).zip(nil)
=> [[4, nil], [5, nil], [6, nil]]

note that this doesn’t work in the current version:

irb(main):001:0> RUBY_VERSION
=> “1.9.0”
irb(main):002:0> (4…6).zip(nil)
TypeError: cannot convert nil into Array
from (irb):2:in `zip’
from (irb):2

I also use 1.9… but gets different result.
What date does your ‘ruby -v’ tell?

ruby -v
ruby 1.9.0 (2004-04-06) [i386-freebsd5.1]
irb
irb(main):001:0> (4…6).zip(nil)
=> [[4, nil], [5, nil], [6, nil]]
irb(main):002:0>

Maybe are missing the point of what zip does… when you call #zip, it
ensures the object you pass to it is an array; then it zips it. I’m
guessing #zip calls to_a on it…

What you described is the behavier of Ruby-1.8.1.

I should have mentioned that I am using 1.9

ruby -v
ruby 1.9.0 (2004-04-06) [i386-freebsd5.1]

But I may be misunderstanding your proposal… Isn’t what you are
proposing something like this?

irb(main):003:0> (4…6).map{|i|[i,‘a’]}
=> [[4, “a”], [5, “a”], [6, “a”]]

(as was suggested by daz elsewhere in the thread)

No, thats the subject of another thread…
that is not what my proposal is about.

My proposal is about changing the current behavier of 1.9,
so that it does padding, rather than placing all the
supplied arguments to the first element only.

The current behavier
irb(main):001:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, nil], [6, nil]]
irb(main):002:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, nil, nil], [6, nil, nil]]
irb(main):003:0>

Proposed behavier
irb(main):001:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, “a”], [6, “a”]]
irb(main):002:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]
irb(main):003:0>

···

On Mon, 12 Apr 2004 17:24:01 +0900, Mark Hubbart wrote:

On Apr 11, 2004, at 6:59 PM, Simon Strandgaard wrote:


Simon Strandgaard

Yes padding can be accomplished with map (requires
sligthly more typing).

The reason I propose it, is that I think this a more
useful behavier of zip, rather than the current behavier
where it only pads the first element.

I have interest in #zip’s behavier, if there is oddities
then I ask why… With 1.9 #zip has been extended, this
proposal is about fixing the behavier of that extension.

···

On Mon, 12 Apr 2004 07:40:29 +0100, daz wrote:

Simon Strandgaard wrote:

It would be awesome if #zip could do the same
with non-nil elements… (this is what I propose)

p (4…6).zip(‘a’, ‘b’)
#=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]

p (4…6).map {|n| [n, ‘a’, ‘b’]}

#=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]


Simon Strandgaard

How do you propose to distinguish between normal arguments to #zip and padding
arguments to it? That is, when I call:

[a, b, c].zip([1, 2, 3], [4, 5, 6])

How do you know which of the following the output should be:

[ [a, 1, 4], [b, 2, 5], [c, 3, 6] ]

[ [a, 1, [4, 5, 6] ], [b, 2, [4, 5, 6] ], [c, 3, [4, 5, 6] ] ]

[ [a, [1, 2, 3], [4, 5, 6] ],
  [b, [1, 2, 3], [4, 5, 6] ],
  [c, [1, 2, 3], [4, 5, 6] ] ]

The first is what it should be (by current standards), but the latter two are
both valid if you can pad with values. And if enumerables are always zipped
as in the first one, how do I pad with array values?

I don’t think you can work that out. You could pad with any value, but you
have to standardize it, because I don’t see how you can reliably distinguish
between values-to-pad-with and values-to-zip-with. nil just makes the most
sense for a standard padding value. The reason it places your arguments
only in the first cell and pads with nil is that it thinks you’re zipping with
two one-element arrays (string.to_a => [string]).

  • Dan

I also use 1.9… but gets different result.
What date does your ‘ruby -v’ tell?

ruby -v
ruby 1.9.0 (2004-04-06) [i386-freebsd5.1]
irb
irb(main):001:0> (4…6).zip(nil)
=> [[4, nil], [5, nil], [6, nil]]
irb(main):002:0>

okay, I guess that particular release (2004-02-21) of 1.9 was flawed :slight_smile:
I got the latest snapshot and the error went away. #to_a was not
implemented for nil in that release. However, now (4…6).zip(1) doesn’t
work, since Fixnum#to_a is not implemented. hmmm…

I remember a warning on 1.8, I believe, hat stated that Object#to_a was
being deprecated, and may be removed in future versions. Perhaps this
is the result?

Maybe are missing the point of what zip does… when you call #zip, it
ensures the object you pass to it is an array; then it zips it. I’m
guessing #zip calls to_a on it…

What you described is the behavier of Ruby-1.8.1.

I should have mentioned that I am using 1.9

ruby -v
ruby 1.9.0 (2004-04-06) [i386-freebsd5.1]

But I may be misunderstanding your proposal… Isn’t what you are
proposing something like this?

irb(main):003:0> (4…6).map{|i|[i,‘a’]}
=> [[4, “a”], [5, “a”], [6, “a”]]

(as was suggested by daz elsewhere in the thread)

No, thats the subject of another thread…
that is not what my proposal is about.

My proposal is about changing the current behavier of 1.9,
so that it does padding, rather than placing all the
supplied arguments to the first element only.

The current behavier
irb(main):001:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, nil], [6, nil]]
irb(main):002:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, nil, nil], [6, nil, nil]]
irb(main):003:0>

Proposed behavier
irb(main):001:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, “a”], [6, “a”]]
irb(main):002:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]
irb(main):003:0>

As pointed out by someone else, how should we determine when to pad
with an object, and when to zip? Only zip if the object implements
#to_ary? or #each? or, perhaps, #next?

Perhaps if you would post some code it would clear this up, so that it
would be obvious what the behavior would be.

Note that I’m not against it; I just want to know how it would work. If
you can get it to work intuitively, then I would be all for it. :slight_smile:

–Mark

···

On Apr 12, 2004, at 5:29 AM, Simon Strandgaard wrote:

How do you propose to distinguish between normal arguments
to #zip and padding arguments to it? That is, when I call:

[a, b, c].zip([1, 2, 3], [4, 5, 6])

If it includes Enumerable, then its a normal argument.
That would be: Array, String, …

If it doesn’t its a padding argument.
That would be: NilClass, Fixnum, …

How do you know which of the following the output should be:

[ [a, 1, 4], [b, 2, 5], [c, 3, 6] ]

In your case, you have supplied 2 arrays to zip
[a, b, c].zip([1, 2, 3], [4, 5, 6])

so you will get above output… nothing changed here.

However if you had chosen a value which didn’t were compatible with
Enumerable… then it could be
[a, b, c].zip([1, 2, 3], 4)
#=> [ [a, 1, 4], [b, 2, 4], [c, 3, 4] ]

I don’t think you can work that out. You could pad with any value, but you
have to standardize it, because I don’t see how you can reliably distinguish
between values-to-pad-with and values-to-zip-with. nil just makes the most
sense for a standard padding value. The reason it places your arguments
only in the first cell and pads with nil is that it thinks you’re zipping with
two one-element arrays (string.to_a => [string]).

Yes, true… I forgot to mention how to distinguish between normal and padding.
If the instance includes the Enumerable module, then normal.
otherwise its a padding argument.

Is it more clear now ?

BTW: How can I make it more clear?

···

On Tue, 13 Apr 2004 01:01:40 +0900, Dan Doel wrote:


Simon Strandgaard

My proposal is about changing the current behavier of 1.9,
so that it does padding, rather than placing all the
supplied arguments to the first element only.

The current behavier
irb(main):001:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, nil], [6, nil]]
irb(main):002:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, nil, nil], [6, nil, nil]]
irb(main):003:0>

Proposed behavier
irb(main):001:0> (4…6).zip(‘a’)
=> [[4, “a”], [5, “a”], [6, “a”]]
irb(main):002:0> (4…6).zip(‘a’, ‘b’)
=> [[4, “a”, “b”], [5, “a”, “b”], [6, “a”, “b”]]
irb(main):003:0>

As pointed out by someone else, how should we determine when to pad
with an object, and when to zip? Only zip if the object implements
#to_ary? or #each? or, perhaps, #next?

Bommer, in the above example I have passed Strings to zip, which
includes Enumerable. I thought about using Enumerable to destinguish
between padding elements and normal elements.

However Fixnum doesn’t include Enumerable, so the example would be:
irb(main):001:0> (4…6).zip(666)
=> [[4, 666], [5, 666], [6, 666]]
irb(main):002:0> (4…6).zip(:a, :b)
=> [[4, :a, :b], [5, :a, :b], [6, :a, :b]]
irb(main):003:0>

It seems as if the current #zip uses Enumerable. Thats why I thought
to continue using Enumerable… Any ideas to distinguish by other
means?

Perhaps if you would post some code it would clear this up, so that it
would be obvious what the behavior would be.

I have posted an example in the other thread
http://ruby-talk.org/97006
However it doesn’t distinguish by if Enumerable is included,
nor uses continuations.

Maybe I will clean up the example by means of ‘enumerator’ ?

Note that I’m not against it; I just want to know how it would work. If
you can get it to work intuitively, then I would be all for it. :slight_smile:

Great with mental support. Its hard to defend proposals.
Its good to hear people open to new ideas.

:wink:

···

On Tue, 13 Apr 2004 07:47:38 +0900, Mark Hubbart wrote:

On Apr 12, 2004, at 5:29 AM, Simon Strandgaard wrote:


Simon Strandgaard

I understand the proposal. I’m just trying to help examine any areas it may
fail in, to make it more robust.

I suppose you could say Enumerables are how you distinguish between zipping
and padding arguments. However, there’s no way to pad with Enumerables, then.
I suppose that might not be a common wish, but there’s that to consider.

Also note that String is Enumerable (enumerates by line), so your example:

(4..6).zip('a', 'b')

Still evaluates to:

[ [4, a, b], [5, nil, nil], [6, nil, nil] ]

And there’s no way to pad with Strings in this scheme.

You noticed this in your reply elsewhere in the thread, and asked for good
ways to separate padding and enumerating values. I just don’t think there
are any intuitive ones. Having variable numbers of arguments that are
semantically different based only on their inheritance hierarchy doesn’t seem
like a good solution to me.

Also, do you say that when argument i is padding, all subsequent arguments i+n
are padding as well? Otherwise all of the following are equivalent:

(4..8).zip(6, 1..2, 5, 2..3)
(4..8).zip(6, 5, 1..2, 2..3)
(4..8).zip(1..2, 6, 5, 2..3)
(4..8).zip(1..2, 2..3, 6, 5)

Which would be confusing. But then, it’s confusing both ways (for me).

Anyhow, I just don’t foresee a solution to this with arguments. The closest I
can come at the moment is this:

(4..8).zip(1..2, 3..5).map { |a, b, c|
	[a, (b.nil? ? 'a' : b), (c.nil? ? 'b' : c)]
}

Which is verbose, but it’s clear what is going on (more or less). It could be
helped by a #zip_and_collect method or something (which is a subject for your
other thread :)).

I just don’t think a pure argument solution will get you there. You’re welcome
to prove me wrong, though.

Cheers.

  • Dan
···

On Monday 12 April 2004 5:49 pm, Simon Strandgaard wrote:

Yes, true… I forgot to mention how to distinguish between normal and
padding. If the instance includes the Enumerable module, then normal.
otherwise its a padding argument.

Is it more clear now ?

BTW: How can I make it more clear?

[snip]

I suppose you could say Enumerables are how you distinguish between zipping
and padding arguments. However, there’s no way to pad with Enumerables, then.
I suppose that might not be a common wish, but there’s that to consider.
[snip]
You noticed this in your reply elsewhere in the thread, and asked for good
ways to separate padding and enumerating values. I just don’t think there
are any intuitive ones. Having variable numbers of arguments that are
semantically different based only on their inheritance hierarchy doesn’t seem
like a good solution to me.
[snip]
I just don’t think a pure argument solution will get you there. You’re welcome
to prove me wrong, though.

Yes… I forgot considering how to distinguish the arguments.
Just when I saw that ‘(4…6).zip(nil)’ was possible, I thought
it might be a good idea if other non-array-like arguments
could be passed to #zip to be used for padding.

Until we find a nicer way to distinguish, I then agree that my
proposal is bad. I don’t have any ideas besides using enumerable.

this proposal has been withdrawen

Thanks for drilling into this :wink:
At least this layed the foundation for the other thread about
#zip taking a block. So your comments hasn’t been wasted effort.
I like loud thinking… it would be a shame to loose good ideas,
just because people keep silent about them. I can only recommend
others to speak out about their ideas. Besides that I am
over-curious to read about what other people are having of ideas.

···

On Tue, 13 Apr 2004 09:23:23 +0900, Dan Doel wrote:


Simon Strandgaard