Better name for #zip_with

Any ideas for a better name for:

[1,2,3].zip_with([6,5,4]) { |a, b| 3 * a + b } #=> [9, 11, 13]

#zip_with comes from Haskell, but I think it’s confusing because of
Ruby’s #zip.

Doesn’t zip basically do that already?

ruby-1.9.2-p180 :001 > l = [1,2,3]; r = [6,5,4]
=> [6, 5, 4]
ruby-1.9.2-p180 :002 > arr = []; l.zip® { |first, second| arr << 3 *
first + second }; arr
=> [9, 11, 13]

(Are you just trying to save the last step?)

~ jf

John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/

IT seems closer to map than zip (IMHO) so maybe map_with ?
OR would cross_product cover it? Maybe too specific…

How about #zip_and_map? Notice that:

a.zip_with(b) { |c, d| … }

is the same as the result of

a.zip(b).map { |c, d| … }

~ jf

John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/

On Jul 17, 10:36pm, John F. [email protected] wrote:

How about #zip_and_map? Notice that:

a.zip_with(b) { |c, d| … }

is the same as the result of

a.zip(b).map { |c, d| … }

Ah, right. #zip_map would makes sense then. But per your last post,
I think I may override #zip itself.

On Jul 17, 10:13pm, John F. [email protected] wrote:

Doesn’t zip basically do that already?

ruby-1.9.2-p180 :001 > l = [1,2,3]; r = [6,5,4]
=> [6, 5, 4]
ruby-1.9.2-p180 :002 > arr = []; l.zip® { |first, second| arr << 3 *
first + second }; arr
=> [9, 11, 13]

(Are you just trying to save the last step?)

Actually, I didn’t know zip took a block. Good to know. So yea, that
makes it much closer than I realized. But why doesn’t it map the
results? That’s unfortunate. I think I will submit a feature request
for Ruby.

Thanks.

On Jul 17, 10:16pm, Chris H. [email protected] wrote:

IT seems closer to map than zip (IMHO) so maybe map_with ?
OR would cross_product cover it? Maybe too specific…

#map_with does read right, doesn’t it. hmm…

Thomas S. wrote in post #1011313:

On Jul 17, 10:36pm, John F. [email protected] wrote:

How about #zip_and_map? Notice that:

a.zip_with(b) { |c, d| … }

is the same as the result of

a.zip(b).map { |c, d| … }

Ah, right. #zip_map would makes sense then. But per your last post,
I think I may override #zip itself.

Not sure whether I find this a good idea. Reason: #map has overhead of
creating a new Array with the same length as the input. That should not
be the default behavior IMHO. A clean separation would be

[].zip([]) => Enumerator
[].zip([]) {|a,b| …} => nil (as today) or self (i.e. leftmost Array)

Then we can efficiently have [].zip([]).map {|a,b| …}

But it would break old code. :frowning:

So, today for efficient zip + map we would have to do

[].enum_for(:zip, []).map {|a,b| …}

Kind regards

robert

On Sun, Jul 24, 2011 at 8:24 AM, Christopher D. [email protected]
wrote:

a.zip(b).map { |c, d| … }
would be returned by the Enumerator that would be returned by the
non-block form of #zip.

What exactly do you mean? #to_enum does not honor a block:

irb(main):001:0> a=5.times.to_a
=> [0, 1, 2, 3, 4]
irb(main):002:0> b=a.to_enum(:map) {|x|x*2}
=> #<Enumerator: [0, 1, 2, 3, 4]:map>
irb(main):003:0> b.to_a
=> [0, 1, 2, 3, 4]

Did you mean Generator?

irb(main):012:0> b=Enumerator.new {|y| a.each {|x| y << x*2}}
=> #<Enumerator: #Enumerator::Generator:0x106afc60:each>
irb(main):013:0> b.to_a
=> [0, 2, 4, 6, 8]

With #zip

irb(main):014:0> b=a.dup
=> [0, 1, 2, 3, 4]
irb(main):015:0> i=Enumerator.new {|y| a.zip(b){|m,n| y << m - n} }
=> #<Enumerator: #Enumerator::Generator:0x1066d248:each>
irb(main):016:0> i.to_a
=> [0, 0, 0, 0, 0]

Kind regards

robert

On Mon, Jul 18, 2011 at 10:25 AM, Robert K.
[email protected] wrote:

Ah, right. #zip_map would makes sense then. But per your last post,
I think I may override #zip itself.

Not sure whether I find this a good idea. Reason: #map has overhead of
creating a new Array with the same length as the input. That should not
be the default behavior IMHO.

So, don’t do that; just return an Enumerator that returns the
successive results of applying the given block to the elements that
would be returned by the Enumerator that would be returned by the
non-block form of #zip.

On Jul 18, 1:25pm, Robert K. [email protected] wrote:

Then we can efficiently have [].zip([]).map {|a,b| …}

But it would break old code. :frowning:

So, today for efficient zip + map we would have to do

[].enum_for(:zip, []).map {|a,b| …}

Thanks. If I add to Facets I’ll utilize this.

I’m starting to think, however, that it makes more sense to add
optional arguments to #map itself. Consider that #zip returns an assoc
array, that’s it’s expected behavior. So it’s probably best not to
alter that. Whereas map can return any form of array based on the
block.

[1,2,3].map([2,3,4], [5,6,7]) { |a,b,c| ... }

Map has free arguments, so why not?

On Mon, Jul 25, 2011 at 1:16 AM, Intransition [email protected]
wrote:

I’m starting to think, however, that it makes more sense to add
optional arguments to #map itself. Consider that #zip returns an assoc
array, that’s it’s expected behavior. So it’s probably best not to
alter that. Whereas map can return any form of array based on the
block.

[1,2,3].map([2,3,4], [5,6,7]) { |a,b,c| … }

Wouldn’t that be

[1,2,3].map([2,3,4], [5,6,7]) { |a,b| … }

?

Map has free arguments, so why not?

Orthogonality probably. And it is not entirely clear whether map +
zip is the most common or most useful use. Others may want to use
arguments to #map for #grep like selection or even other uses. Who
decides which use wins and becomes standard?

Kind regards

robert

What about cutting to the point of the method and calling it #zip_map
(first
zip, then map)? It isn’t as readable but it avoids the misleading parts
of
#zip_with and the introduction of zipping functionality to #map.