# Parallel Array

**URL:** <https://rubytalk.org/t/parallel-array/28641>\
**Category:** ruby-talk\
**Created:** [5 July 2006 00:16 UTC](https://rubytalk.org/t/parallel-array/28641 "2006-07-05T00:16:18Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nasir\_Khan](https://avatars.discourse-cdn.com/v4/letter/n/5daacb/32.png) [@Nasir\_Khan](https://rubytalk.org/u/Nasir_Khan)\
**Post date:** [5 July 2006 00:16 UTC](https://rubytalk.org/t/parallel-array/28641/1 "2006-07-05T00:16:18Z")

</div>

If I have two arrays a=[1,1,1,1] and b=[2,2,2,2] and I want to add each  
element up, something like -

c = a plus b =\> [3,3,3,3]

One way I could think up is -

irb(main):010:0\> (0...a.length).collect{|k| a[k]+b[k]}  
=\> [3, 3, 3, 3]

Is there a better/faster way?

Thanks  
Nasir

---

<div class="post-metadata">

**Author:** ![Phillip\_Hutchings](https://avatars.discourse-cdn.com/v4/letter/p/f08c70/32.png) [@Phillip\_Hutchings](https://rubytalk.org/u/Phillip_Hutchings)\
**Post date:** [5 July 2006 00:21 UTC](https://rubytalk.org/t/parallel-array/28641/2 "2006-07-05T00:21:24Z")

</div>

a.zip(b).collect{|x| x.inject{|q, r| q+r}}

> **···**
>
> On 7/5/06, Nasir Khan \<rubylearner@gmail.com\> wrote:
> 
> > If I have two arrays a=[1,1,1,1] and b=[2,2,2,2] and I want to add each  
> > element up, something like -
> > 
> > c = a plus b =\> [3,3,3,3]
> > 
> > One way I could think up is -
> > 
> > irb(main):010:0\> (0...a.length).collect{|k| a[k]+b[k]}  
> > =\> [3, 3, 3, 3]
> > 
> > Is there a better/faster way?
> > 
> > Thanks  
> > Nasir
> 
> --  
> Phillip Hutchings  
> [http://www.sitharus.com/](http://www.sitharus.com/)

---

<div class="post-metadata">

**Author:** ![Matthew\_Smillie](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@Matthew\_Smillie](https://rubytalk.org/u/Matthew_Smillie)\
**Post date:** [5 July 2006 00:50 UTC](https://rubytalk.org/t/parallel-array/28641/3 "2006-07-05T00:50:46Z")

</div>

This is probably the simplest:

# Arrays have constructors too!  
c = Array.new(a.length) { |i| a[i] + b[i] }

These are more fun/complicated.

# initialise and fill in place.  
c = .fill(0...a.length) { |i| a[i] + b[i] }

# use inject, it's good for job security.  
c = a.zip(b).map { |x| x.inject(0) { |s, n| s + n } }

# using inject is fun. Let's do it again.  
c = (0...a.length).inject() { |x, n| x \<\< a[n] + b[n] }

I don't think there are any actual efficiency gains to be made, to tell the truth. The direct initialisation is possibly very slightly more efficient (fewer method calls, fewer intermediate arrays created), but I doubt that the difference would be distinguishable from noise in an actual application. The only reason I'm not 100% fond of the block constructor is that its semantics are quite different from the syntactically-similar Hash constructor with a default block, but that's a pretty subjective quibble.

matthew smillie.

> **···**
>
> On Jul 5, 2006, at 1:16, Nasir Khan wrote:
> 
> > If I have two arrays a=[1,1,1,1] and b=[2,2,2,2] and I want to add each  
> > element up, something like -
> > 
> > c = a plus b =\> [3,3,3,3]
> > 
> > One way I could think up is -
> > 
> > irb(main):010:0\> (0...a.length).collect{|k| a[k]+b[k]}  
> > =\> [3, 3, 3, 3]
> > 
> > Is there a better/faster way?

---

<div class="post-metadata">

**Author:** ![\_Pena\_Botp1](https://avatars.discourse-cdn.com/v4/letter/_/94ad74/32.png) [@\_Pena\_Botp1](https://rubytalk.org/u/_Pena_Botp1)\
**Post date:** [5 July 2006 02:24 UTC](https://rubytalk.org/t/parallel-array/28641/4 "2006-07-05T02:24:42Z")

</div>

fr Nasir:  
# irb(main):010:0\> (0...a.length).collect{|k| a[k]+b[k]}  
# =\> [3, 3, 3, 3]

looks clear to me 🙂

# Is there a better/faster way?

i do not go for faster, but maybe simpler to the eye,

c=[]  
a.each\_index{|i| c \<\< a[i]+b[i]}

kind regards -botp

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard6](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@Ara.T.Howard6](https://rubytalk.org/u/Ara.T.Howard6)\
**Post date:** [5 July 2006 04:54 UTC](https://rubytalk.org/t/parallel-array/28641/5 "2006-07-05T04:54:15Z")

</div>

harp:~ \> cat a.rb  
# gem install narray  
require 'narray'

a = NArray.to\_na [1,1,1,1]  
b = NArray.to\_na [2,2,2,2]

p a + b

harp:~ \> ruby a.rb  
NArray.int(4):  
[3, 3, 3, 3]

-a

> **···**
>
> On Wed, 5 Jul 2006, Nasir Khan wrote:
> 
> > If I have two arrays a=[1,1,1,1] and b=[2,2,2,2] and I want to add each  
> > element up, something like -
> > 
> > c = a plus b =\> [3,3,3,3]
> > 
> > One way I could think up is -
> > 
> > irb(main):010:0\> (0...a.length).collect{|k| a[k]+b[k]}  
> > =\> [3, 3, 3, 3]
> > 
> > Is there a better/faster way?
> > 
> > Thanks  
> > Nasir
> 
> --  
> suffering increases your inner strength. also, the wishing for suffering  
> makes the suffering disappear.  
> - h.h. the 14th dali lama

---

<div class="post-metadata">

**Author:** ![Daniel\_DeLorme](https://avatars.discourse-cdn.com/v4/letter/d/9d8465/32.png) [@Daniel\_DeLorme](https://rubytalk.org/u/Daniel_DeLorme)\
**Post date:** [5 July 2006 05:17 UTC](https://rubytalk.org/t/parallel-array/28641/6 "2006-07-05T05:17:56Z")

</div>

Nasir Khan wrote:

> If I have two arrays a=[1,1,1,1] and b=[2,2,2,2] and I want to add each  
> element up, something like -
> 
> c = a plus b =\> [3,3,3,3]
> 
> One way I could think up is -
> 
> irb(main):010:0\> (0...a.length).collect{|k| a[k]+b[k]}  
> =\> [3, 3, 3, 3]
> 
> Is there a better/faster way?

I'm not sure about faster, but this is probably more readable:

irb(main):001:0\> require "matrix"  
=\> true  
irb(main):002:0\> Vector[1,1,1,1] + Vector[2,2,2,2]  
=\> Vector[3, 3, 3, 3]

Daniel

---

<div class="post-metadata">

**Author:** ![Greg\_Brown1](https://avatars.discourse-cdn.com/v4/letter/g/258eb7/32.png) [@Greg\_Brown1](https://rubytalk.org/u/Greg_Brown1)\
**Post date:** [5 July 2006 02:36 UTC](https://rubytalk.org/t/parallel-array/28641/7 "2006-07-05T02:36:31Z")

</div>

better would be c = (0...a.length).inject() { |x, n| x + [a[n] + b[n] ] }

The example you showed breaks the functional aspect of inject.  
(it is doing double assignment)

I just learned to avoid this myself....

> **···**
>
> On 7/4/06, Matthew Smillie \<M.B.Smillie@sms.ed.ac.uk\> wrote:
> 
> > # using inject is fun. Let's do it again.  
> > c = (0...a.length).inject() { |x, n| x \<\< a[n] + b[n] }

---

<div class="post-metadata">

**Author:** ![Sean\_O\_Halpin](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Sean\_O\_Halpin](https://rubytalk.org/u/Sean_O_Halpin)\
**Post date:** [5 July 2006 03:13 UTC](https://rubytalk.org/t/parallel-array/28641/8 "2006-07-05T03:13:55Z")

</div>

I like this:

&nbsp;&nbsp;a.zip(b).map{|(x,y)| x + y}

Not as fast as the Array.new(size) version, but the block doesn't need  
to know which arrays it's operating on.

BTW, does anyone know why zip with a block returns nil? It would be  
handy to have it map.

Regards,  
Sean

> **···**
>
> On 7/5/06, Peña, Botp \<botp@delmonte-phil.com\> wrote:
> 
> > i do not go for faster, but maybe simpler to the eye,
> > 
> > c=  
> > a.each\_index{|i| c \<\< a[i]+b[i]}
> > 
> > kind regards -botp

---

<div class="post-metadata">

**Author:** ![\_Pena\_Botp1](https://avatars.discourse-cdn.com/v4/letter/_/94ad74/32.png) [@\_Pena\_Botp1](https://rubytalk.org/u/_Pena_Botp1)\
**Post date:** [5 July 2006 03:44 UTC](https://rubytalk.org/t/parallel-array/28641/9 "2006-07-05T03:44:01Z")

</div>

Sean wrote:  
# Botp wrote:  
# \> i do not go for faster, but maybe simpler to the eye,  
# \>  
# \> c=[]  
# \> a.each\_index{|i| c \<\< a[i]+b[i]}  
# \>  
# \> kind regards -botp  
# \>  
# I like this:

> **···**
>
> #  
> # a.zip(b).map{|(x,y)| x + y}
> 
> Yes, Sean, zip w map is cool, really. (i think you can lose the parens, too).  
> Zip allows any number of arrays. so now we have to keep track of how many arrays we are zipping.
> 
> irb(main):002:0\> a=[1,2,3]  
> =\> [1, 2, 3]  
> irb(main):003:0\> b=[4,5,6]  
> =\> [4, 5, 6]  
> irb(main):004:0\> c=[7,8,9]  
> =\> [7, 8, 9]  
> irb(main):005:0\> a.zip(b).map{|x,y| x + y }  
> =\> [5, 7, 9]  
> irb(main):007:0\> a.zip(b,c).map{|x,y,z| x + y + z }  
> =\> [12, 15, 18]
> 
> Maybe, we just create a Array#sum to simplify and scale further, like so,
> 
> irb(main):016:0\> a.zip(b).map{|e| e.sum}  
> =\> [5, 7, 9]  
> irb(main):017:0\> a.zip(b,c).map{|e| e.sum}  
> =\> [12, 15, 18]
> 
> no change in inside block. ruby is cool.
> 
> # Not as fast as the Array.new(size) version, but the block doesn't need  
> # to know which arrays it's operating on.
> 
> and no length/size pre-det, too 🙂
> 
> # BTW, does anyone know why zip with a block returns nil? It would be  
> # handy to have it map.
> 
> maybe, ruby is trying to tell us beware. if we screw our block, we might get bloated run-away arrays. maybe we should map to be sure...
> 
> kind regards -botp
> 
> # Regards,  
> # Sean

---

<div class="post-metadata">

**Author:** ![Logan\_Capaldo](https://avatars.discourse-cdn.com/v4/letter/l/7ea924/32.png) [@Logan\_Capaldo](https://rubytalk.org/u/Logan_Capaldo)\
**Post date:** [5 July 2006 04:44 UTC](https://rubytalk.org/t/parallel-array/28641/10 "2006-07-05T04:44:20Z")

</div>

#zip with a block acts as an #each style iterator:

% cat zip\_example.rb  
a = [1, 2, 3]  
b = [4, 5, 6]

a.zip(b) do |a\_elem, b\_elem|  
&nbsp;&nbsp;&nbsp;p [a\_elem, b\_elem]  
end

% ruby zip\_example.rb  
[1, 4]  
[2, 5]  
[3, 6]

You either get the #map style functionality or the #each style functionality. #each is more general, e.g.:

a.to\_enum(:zip, b).map { |x, y| ... }

so it makes sense to me that it's nto a map with a block.

> **···**
>
> On Jul 4, 2006, at 11:13 PM, Sean O'Halpin wrote:
> 
> > BTW, does anyone know why zip with a block returns nil? It would be  
> > handy to have it map.

---

<div class="post-metadata">

**Author:** ![Mauricio\_Fernandez](https://avatars.discourse-cdn.com/v4/letter/m/73ab20/32.png) [@Mauricio\_Fernandez](https://rubytalk.org/u/Mauricio_Fernandez)\
**Post date:** [5 July 2006 10:32 UTC](https://rubytalk.org/t/parallel-array/28641/11 "2006-07-05T10:32:30Z")

</div>

ugh this is doubly slow. #inject, an extra literal array and an Array#+ for  
each pair, making it O(n\*\*2)...

If you absolutely want to feel smart for using #inject,

a = [1,2,3,4]  
b = [1,1,2,2]  
c = a.inject([,0]){|(arr, i),e| [arr \<\< e+b[i], i + 1]}.first  
c # =\> [2, 3, 5, 6]

... but it's still silly. Either use the Array initializer, manual aref in a  
a.size.times block, or look into narray.

> **···**
>
> On Wed, Jul 05, 2006 at 11:36:31AM +0900, Gregory Brown wrote:
> 
> > On 7/4/06, Matthew Smillie \<M.B.Smillie@sms.ed.ac.uk\> wrote:
> > 
> > \># using inject is fun. Let's do it again.  
> > \>c = (0...a.length).inject() { |x, n| x \<\< a[n] + b[n] }
> > 
> > better would be c = (0...a.length).inject() { |x, n| x + [a[n] + b[n] ] }
> 
> --  
> Mauricio Fernandez - [http://eigenclass.org](http://eigenclass.org) - singular Ruby

---

<div class="post-metadata">

**Author:** ![Sean\_O\_Halpin](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Sean\_O\_Halpin](https://rubytalk.org/u/Sean_O_Halpin)\
**Post date:** [5 July 2006 05:08 UTC](https://rubytalk.org/t/parallel-array/28641/12 "2006-07-05T05:08:59Z")

</div>

> Sean wrote:  
> # Botp wrote:  
> # \> i do not go for faster, but maybe simpler to the eye,  
> # \>  
> # \> c=  
> # \> a.each\_index{|i| c \<\< a[i]+b[i]}  
> # \>  
> # \> kind regards -botp  
> # \>  
> # I like this:  
> #  
> # a.zip(b).map{|(x,y)| x + y}
> 
> Yes, Sean, zip w map is cool, really. (i think you can lose the parens, too).

Hmm.. wonder what I was doing there?

> Zip allows any number of arrays. so now we have to keep track of how many arrays we are zipping

.  
Good point.

[snip zip examples]

> Maybe, we just create a Array#sum to simplify and scale further, like so,

# here's one way to do it:  
module Enumerable  
&nbsp;&nbsp;def sum(initial = 0)  
&nbsp;&nbsp;&nbsp;&nbsp;inject(initial) { |acc, el| acc + el }  
&nbsp;&nbsp;end  
end

> irb(main):016:0\> a.zip(b).map{|e| e.sum}  
> =\> [5, 7, 9]  
> irb(main):017:0\> a.zip(b,c).map{|e| e.sum}  
> =\> [12, 15, 18]
> 
> no change in inside block. ruby is cool.

Certainly is 🙂

For example:

module Enumerable  
&nbsp;&nbsp;def zip\_map(\*args, &block)  
&nbsp;&nbsp;&nbsp;&nbsp;zip(\*args).map( &block )  
&nbsp;&nbsp;end  
end  
# and with nobu's definition of Symbol#to\_proc  
class Symbol  
&nbsp;&nbsp;def to\_proc  
&nbsp;&nbsp;&nbsp;&nbsp;Proc.new{|\*args| args.shift.\_\_send\_\_(self, \*args)}  
&nbsp;&nbsp;end  
end

# we could do this:  
a=[1,1,1,1]  
b=[2,2,2,2]  
c=[3,3,3,3]  
p a.zip\_map(b, c, &:sum)  
#=\> [6, 6, 6, 6]

This isn't particularly fast though!

Regards,  
Sean

> **···**
>
> On 7/5/06, Peña, Botp \<botp@delmonte-phil.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Sean\_O\_Halpin](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Sean\_O\_Halpin](https://rubytalk.org/u/Sean_O_Halpin)\
**Post date:** [5 July 2006 05:18 UTC](https://rubytalk.org/t/parallel-array/28641/13 "2006-07-05T05:18:13Z")

</div>

It's not quite the same - each returns the receiver not nil. I was  
wondering what the rationale of zip returning nil was. It would be  
more consistent to return the receiver and perhaps handier to act like  
map. No big deal though.

Regards,  
Sean

> **···**
>
> On 7/5/06, Logan Capaldo \<logancapaldo@gmail.com\> wrote:
> 
> > On Jul 4, 2006, at 11:13 PM, Sean O'Halpin wrote:
> > 
> > \> BTW, does anyone know why zip with a block returns nil? It would be  
> > \> handy to have it map.
> > 
> > #zip with a block acts as an #each style iterator:

---

<div class="post-metadata">

**Author:** ![Mike\_Berrow](https://avatars.discourse-cdn.com/v4/letter/m/f9ae1b/32.png) [@Mike\_Berrow](https://rubytalk.org/u/Mike_Berrow)\
**Post date:** [5 July 2006 08:07 UTC](https://rubytalk.org/t/parallel-array/28641/14 "2006-07-05T08:07:38Z")

</div>

# Here is another variation (using Symbol#to\_proc)  
class Symbol  
&nbsp;&nbsp;def to\_proc  
&nbsp;&nbsp;&nbsp;&nbsp;Proc.new { |obj, \*args| obj.send(self, \*args) }  
&nbsp;&nbsp;end  
end

class Array  
&nbsp;&nbsp;def c2(a) # parallel collect  
&nbsp;&nbsp;&nbsp;&nbsp;(0 .. size - 1).collect {|i| yield self[i], a[i]}  
&nbsp;&nbsp;end  
&nbsp;&nbsp;def c2op(a,opb)  
&nbsp;&nbsp;&nbsp;&nbsp;c2(a,&opb)  
&nbsp;&nbsp;end  
end

# Use with a following block  
p [4,3,2,1].c2([2,2,2,2]) {|a,b| a+b}  
# =\> [6, 5, 4, 3]

# or just send the desired operator as a symbol  
a=[4,3,2,1]  
b=[2,2,2,2]  
p a.c2op(b, :+)  
# =\> [6, 5, 4, 3]

# ... or even re-define addition, subtraction etc.  
class Array  
&nbsp;&nbsp;def +(b)  
&nbsp;&nbsp;&nbsp;&nbsp;self.c2op(b, :+)  
&nbsp;&nbsp;end  
&nbsp;&nbsp;def -(b)  
&nbsp;&nbsp;&nbsp;&nbsp;self.c2op(b, 🙂  
&nbsp;&nbsp;end  
end

a=[4,3,2,1]  
b=[2,2,2,2]  
p a + b  
# =\> [6, 5, 4, 3]  
p a - b  
# =\> [2, 1, 0, -1]

-- Mike Berrow

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Logan\_Capaldo](https://avatars.discourse-cdn.com/v4/letter/l/7ea924/32.png) [@Logan\_Capaldo](https://rubytalk.org/u/Logan_Capaldo)\
**Post date:** [5 July 2006 16:09 UTC](https://rubytalk.org/t/parallel-array/28641/15 "2006-07-05T16:09:10Z")

</div>

Well there's no rational in array.c's comments so I have no idea.

(the code is just return Qnil; )

> **···**
>
> On Jul 5, 2006, at 1:18 AM, Sean O'Halpin wrote:
> 
> > On 7/5/06, Logan Capaldo \<logancapaldo@gmail.com\> wrote:
> > 
> > > On Jul 4, 2006, at 11:13 PM, Sean O'Halpin wrote:
> > > 
> > > \> BTW, does anyone know why zip with a block returns nil? It would be  
> > > \> handy to have it map.
> > > 
> > > #zip with a block acts as an #each style iterator:
> > 
> > It's not quite the same - each returns the receiver not nil. I was  
> > wondering what the rationale of zip returning nil was. It would be  
> > more consistent to return the receiver and perhaps handier to act like  
> > map. No big deal though.
> > 
> > Regards,  
> > Sean

---

<div class="post-metadata">

**Author:** ![Austin\_Ziegler5](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/austin_ziegler5/32/1985_2.png) [@Austin\_Ziegler5](https://rubytalk.org/u/Austin_Ziegler5)\
**Post date:** [5 July 2006 16:19 UTC](https://rubytalk.org/t/parallel-array/28641/16 "2006-07-05T16:19:01Z")

</div>

The word is rationale. It isn't rational for people to use "rational"  
when they mean "rationale." Better, use "explanation."

Not trying to pick on you, Logan, but there've been a \*lot\* of cases  
in the last two weeks where people have used "rational" when they  
meant "rationale" or "explanation." Different parts of speech.

-austin

> **···**
>
> On 7/5/06, Logan Capaldo \<logancapaldo@gmail.com\> wrote:
> 
> > Well there's no rational in array.c's comments so I have no idea.
> 
> --  
> Austin Ziegler \* halostatue@gmail.com \* [http://www.halostatue.ca/](http://www.halostatue.ca/)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\* austin@halostatue.ca \* [You are in a maze of twisty little passages, all alike. // halo • statue](http://www.halostatue.ca/feed/)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\* austin@zieglers.ca
