How to operate on 2 arrays simultaneously?

There has got to be a more elegant solution than this. Suppose I have
2 identical length arrays that I want to add together to produce a
third array. The best solution I've come up with is:

c = (0...a.size).map {|i| a[i] + b[i]}

Any suggestions?

--wpd

a.zip(b).map { |l, r| l + r }

Hope that helps.

James Edward Gray II

···

On Sep 10, 2008, at 10:42 AM, Patrick Doyle wrote:

There has got to be a more elegant solution than this. Suppose I have
2 identical length arrays that I want to add together to produce a
third array. The best solution I've come up with is:

c = (0...a.size).map {|i| a[i] + b[i]}

Any suggestions?

cfp:~ > cat a.rb
a = 0,1,2
b = 3,4,5

c = a.zip(b).map{|pair| pair.first + pair.last}
p c

c = Array.new(a.size){|i| a[i] + b[i]}
p c

cfp:~ > ruby a.rb
[3, 5, 7]

the second is far more efficient for large arrays - in terms of memory.

a @ http://codeforpeople.com/

···

On Sep 10, 2008, at 9:42 AM, Patrick Doyle wrote:

There has got to be a more elegant solution than this. Suppose I have
2 identical length arrays that I want to add together to produce a
third array. The best solution I've come up with is:

c = (0...a.size).map {|i| a[i] + b[i]}

Any suggestions?

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

There has got to be a more elegant solution than this.

I use .each_with_index to walk parallel arrays:

a=[1,2,3]
b=%w(x y z)
a.each_with_index do |item,index|
  puts "item=#{item} index=#{index} a[#{index}]=#{a[index]} b[#{index}]=#{b[index]}"
end

Patrick Doyle wrote:

There has got to be a more elegant solution than this. Suppose I have
2 identical length arrays that I want to add together to produce a
third array. The best solution I've come up with is:

c = (0...a.size).map {|i| a[i] + b[i]}

Any suggestions?

--wpd

http://www.ruby-doc.org/stdlib/libdoc/matrix/rdoc/classes/Matrix.html

···

--
Posted via http://www.ruby-forum.com/\.

Take a look at the zip method.

Jamey

···

On Wed, Sep 10, 2008 at 11:59 AM, DanDiebolt.exe <dandiebolt@yahoo.com> wrote:

There has got to be a more elegant solution than this.

I use .each_with_index to walk parallel arrays:

a=[1,2,3]
b=%w(x y z)
a.each_with_index do |item,index|
puts "item=#{item} index=#{index} a[#{index}]=#{a[index]} b[#{index}]=#{b[index]}"
end

So did I until the other answers in this thread taught me about zip! :slight_smile:
m.

···

DanDiebolt.exe <dandiebolt@yahoo.com> wrote:

>There has got to be a more elegant solution than this.

I use .each_with_index to walk parallel arrays:

--
matt neuburg, phd = matt@tidbits.com, Matt Neuburg’s Home Page
Leopard - http://www.takecontrolbooks.com/leopard-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com

a = 0,1,2
b = 3,4,5

c = a.zip(b).map{|pair| pair.first + pair.last}

Arrghh!
I looked at zip and, for some reason completely missed the fact that
it constructs an array of arrays. For some reason, I decided that it
simply interweaved the two arrays. That's what I was looking for.

c = Array.new(a.size){|i| a[i] + b[i]}
the second is far more efficient for large arrays - in terms of memory.

ok, I can see that.

Thanks for the tips.

--wpd

Well, if you want to avoid the temp Array you can do

irb(main):001:0> a = 0,1,2
=> [0, 1, 2]
irb(main):002:0> b = 3,4,5
=> [3, 4, 5]
irb(main):003:0> a.to_enum(:zip, b).map {|x,y| x + y}
=> [3, 5, 7]

Cheers

  robert

···

On 10.09.2008 17:55, ara.t.howard wrote:

c = a.zip(b).map{|pair| pair.first + pair.last}

c = Array.new(a.size){|i| a[i] + b[i]}

the second is far more efficient for large arrays - in terms of memory.

Yeah, that's probably what I would do for a simple script. I haven't
checked memory usage, but it is elegant IMHO. Probably best for very
large arrays.

a = 1, 2, 3, 4
b = 4, 3, 2, 1
(Matrix[a] + Matrix[b]).to_a.flatten

=> [5, 5, 5, 5]

Todd

···

On Thu, Sep 11, 2008 at 2:02 PM, Peter Bunyan <peter.bunyan@gmail.com> wrote:

Patrick Doyle wrote:

There has got to be a more elegant solution than this. Suppose I have
2 identical length arrays that I want to add together to produce a
third array. The best solution I've come up with is:

c = (0...a.size).map {|i| a[i] + b[i]}

Any suggestions?

--wpd

http://www.ruby-doc.org/stdlib/libdoc/matrix/rdoc/classes/Matrix.html

be careful with zip

a = big
b = big

huge_new_array = a.zip(b)

another_huge_new_array = huge_new_array.each{|a,b| a + b}

using something like each_with_index constructs no new array

a @ http://codeforpeople.com/

···

On Sep 10, 2008, at 10:28 AM, matt neuburg wrote:

So did I until the other answers in this thread taught me about zip! :slight_smile:

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Instead of .zip I use .transpose as it is easier to remember and makes more sense mathematically

irb(main):078:0> a=[1,2,3]
=> [1, 2, 3]

irb(main):079:0> b=%w(x y z)
=> ["x", "y", "z"]

irb(main):080:0> [a,b].transpose
=> [[1, "x"], [2, "y"], [3, "z"]]

irb(main):081:0> a.zip(b)
=> [[1, "x"], [2, "y"], [3, "z"]]

I just ran into a similar problem, and I thought it fits into this
thread.

The Vector class defines the collect2() and collect2!() methods, which
conceptually I like very much. So I thought I could just use the same
concept and extend Array like this:

class Array
  def collect2(v) # :yield: e1, e2
    Array.Raise ErrDimensionMismatch if size != v.size
    (0 .. size - 1).collect do
      >i>
      yield self[i], v[i]
    end
  end

  def collect2!(v) # :yield: e1, e2
   Array.Raise ErrDimensionMismatch if size != v.size
    (0 .. size - 1).collect do
      >i>
      self[i] = yield self[i], v[i]
    end
  end
end

After this I can simply do:
a = [1,2,3]
b = [4,5,6]
a.collect2(b){|e1,e2| e1+e2}
=> [5, 7, 9]

Does anybody see anything wrong with this?
If not, it seems such a handy concept that I'm surprised these are not
standard methods of Array. I've had this problem in various forms over
the past and typically reverted to Array#each_index, always thinking
that this is too clumsy for Ruby, but until now I never took the time to
come up with something more elegant (not that I want to take any credit
for this suggestion as I simply copied what's already in Vector).

Todd Benson wrote:

···

On Thu, Sep 11, 2008 at 2:02 PM, Peter Bunyan <peter.bunyan@gmail.com> > wrote:

http://www.ruby-doc.org/stdlib/libdoc/matrix/rdoc/classes/Matrix.html

Yeah, that's probably what I would do for a simple script. I haven't
checked memory usage, but it is elegant IMHO. Probably best for very
large arrays.

a = 1, 2, 3, 4
b = 4, 3, 2, 1
(Matrix[a] + Matrix[b]).to_a.flatten

=> [5, 5, 5, 5]

Todd

--
Posted via http://www.ruby-forum.com/\.

zip takes a block, even in 1.8, though sadly it yields without
accumulating so you have to do it yourself. but this works:

c = ; a.zip(b) {|i, j| c << f(i,j)}

martin

···

On Wed, Sep 10, 2008 at 9:35 AM, ara.t.howard <ara.t.howard@gmail.com> wrote:

be careful with zip

a = big
b = big

huge_new_array = a.zip(b)

another_huge_new_array = huge_new_array.each{|a,b| a + b}

Everything in Ruby is a pointer. If a[0] is a pointer to a "big long
string", then a.zip(b)[0][0] is a pointer to the very same "big long
string" - not a copy of the string. So creating the "huge_new_array"
just creates some new pointers, right? And pointers are very small. So
for huge_new_array to be a problem, the existence of a and b would have
to have been problematic to start with - meaning that they would have to
have huge length. The amount of *data* in the story (stuff like "big
long string") is not increased.

m.

···

ara.t.howard <ara.t.howard@gmail.com> wrote:

be careful with zip

a = big
b = big

huge_new_array = a.zip(b)

--
matt neuburg, phd = matt@tidbits.com, Matt Neuburg’s Home Page
Leopard - http://www.takecontrolbooks.com/leopard-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com

not really

cfp:~ > cat a.rb
mb = 2 ** 20

big = 2 * mb

a = Array.new big
b = a.dup

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

a.zip(b)

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

cfp:~ > ruby a.rb
9616
99104

a @ http://codeforpeople.com/

···

On Sep 10, 2008, at 1:03 PM, matt neuburg wrote:

Everything in Ruby is a pointer. If a[0] is a pointer to a "big long
string", then a.zip(b)[0][0] is a pointer to the very same "big long
string" - not a copy of the string. So creating the "huge_new_array"
just creates some new pointers, right? And pointers are very small. So
for huge_new_array to be a problem, the existence of a and b would have
to have been problematic to start with - meaning that they would have to
have huge length. The amount of *data* in the story (stuff like "big
long string") is not increased.

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

ara.t.howard wrote:

Everything in Ruby is a pointer. If a[0] is a pointer to a "big long
string", then a.zip(b)[0][0] is a pointer to the very same "big long
string" - not a copy of the string. So creating the "huge_new_array"
just creates some new pointers, right? And pointers are very small. So
for huge_new_array to be a problem, the existence of a and b would have
to have been problematic to start with - meaning that they would have to
have huge length. The amount of *data* in the story (stuff like "big
long string") is not increased.

not really

cfp:~ > cat a.rb
mb = 2 ** 20

big = 2 * mb

a = Array.new big
b = a.dup

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

a.zip(b)

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

It's less dramatic when the entries are not nil (or fixnum etc)--I think that's Matt's point.

mb = 2 ** 20

big = 2 * mb

a = Array.new big do |i| "the string for entry #{i}" end
b = a.dup

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

a.zip(b)

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

__END__
213256
322232

···

On Sep 10, 2008, at 1:03 PM, matt neuburg wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

true enough - my point is that the block form is much better when the arrays are big, without it the new array, pointers or not, is created.

cheers.

a @ http://codeforpeople.com/

···

On Sep 10, 2008, at 1:45 PM, Joel VanderWerf wrote:

It's less dramatic when the entries are not nil (or fixnum etc)--I think that's Matt's point.

mb = 2 ** 20

big = 2 * mb

a = Array.new big do |i| "the string for entry #{i}" end
b = a.dup

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

a.zip(b)

memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
puts memory_usage

__END__
213256
322232

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Definitely relevant, too, since the block form is quite sufficient for
the OP's original purpose (and similar stuff where the goal is to
process one array in the light of another); thx for bringing out that
point. m.

···

ara.t.howard <ara.t.howard@gmail.com> wrote:

On Sep 10, 2008, at 1:45 PM, Joel VanderWerf wrote:

> It's less dramatic when the entries are not nil (or fixnum etc)--I
> think that's Matt's point.
>
> mb = 2 ** 20
>
> big = 2 * mb
>
> a = Array.new big do |i| "the string for entry #{i}" end
> b = a.dup
>
> memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
> puts memory_usage
>
> a.zip(b)
>
> memory_usage = `ps -o rss= -p #{Process.pid}`.to_i
> puts memory_usage
>
> __END__
> 213256
> 322232

true enough - my point is that the block form is much better when the
arrays are big, without it the new array, pointers or not, is created.

--
matt neuburg, phd = matt@tidbits.com, Matt Neuburg’s Home Page
Leopard - http://www.takecontrolbooks.com/leopard-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com