Ash
Ash

Reputation: 25642

How to concatenate values inside two arrays in Ruby

Say I have the following two arrays:

a = [1, 0, 2, 1, 6]
b = [0, 5, 5, 6, 1]

I want to create (or modify a or b) an array with the values inside each relative index of the array to be added together, like:

[1, 5, 7, 7, 7]

Is there a elegant (and fast) way to do this without looping over every index in the first array and adding from the second. I have a feeling that map/reduce/inject might be a way to go here, but these methods have always seemed a bit "magical" to me and I never really understood them.

Upvotes: 2

Views: 400

Answers (5)

sinsuren
sinsuren

Reputation: 1754

This is one of the thing you could do.

[[4,5,6], [10,25,16]].transpose.map {|x| x.reduce(:+)}

Even inject would also do the same.

[[10,20,30],[24,52,62]].transpose.map {|a| a.inject(:+)}

and to have more understanding. Please have a look at ruby: sum corresponding members of two or more arrays

Upvotes: 4

Sagar Pandya
Sagar Pandya

Reputation: 9497

All bases seem to be covered by other answers. These are submitted for interest only:

c = b.cycle
#=> #<Enumerator: [0, 5, 5, 6, 1]:cycle> 
a.map { |e| e + c.next }                                                         
#=> [1, 5, 7, 7, 7]

And another way:

a.map { |e| e + b.rotate!.last }
#=> [1, 5, 7, 7, 7] 

BENCHMARKS

Benchmarks (which I am not doing myself any favours by showing) for larger arrays.

require 'fruity'

a = (1..10_000).to_a.shuffle
b = a.shuffle

compare do
  sagar     { ar = a.dup; br = b.dup; c = br.cycle; ar.map { |e| e + c.next } }
  sagar_2   { ar = a.dup; br = b.dup; ar.map { |e| e + br.rotate!.last } }
  cary      { ar = a.dup; br = b.dup; ar.each_index.map { |i| ar[i]+br[i] } }
  surya     { ar = a.dup; br = b.dup; ar.zip(br).map{|v| v.reduce(:+) } }
  surya_2   { ar = a.dup; br = b.dup; ar.map.with_index { |v, i| v + br[i] } }
  sinsuren  { ar = a.dup; br = b.dup; [ar, br].transpose.map {|x| x.reduce(:+)} }
  flamine   { ar = a.dup; br = b.dup; ar.map{|i| br.shift.to_i + i }}
  stefan    { ar = a.dup; br = b.dup; ar.zip(br).map { |i, j| i + j }}
end

#Running each test once. Test will take about 3 seconds.
#flamine is similar to surya_2
#surya_2 is similar to stefan
#stefan is similar to cary
#cary is faster than sinsuren by 3x ± 1.0
#sinsuren is similar to surya
#surya is faster than sagar by 2x ± 0.1
#sagar is faster than sagar_2 by 15x ± 1.0

Ran this a few times, sometimes flamine is outright fastest: flamine is faster than surya_2 by 10.000000000000009% ± 10.0%. The caveat being that flamine's technique modifies b to an empty array.

Upvotes: 4

Flamine
Flamine

Reputation: 487

I like this variant, but its work correctly only if a.size >= b.size

a.map{|i| b.shift.to_i + i }

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110665

a.each_index.map { |i| a[i]+b[i] }
  # => [1, 5, 7, 7, 7]

Upvotes: 4

Surya
Surya

Reputation: 15992

You could zip and then use reduce:

p a.zip(b).map{|v| v.reduce(:+) }
#=> [1, 5, 7, 7, 7]

Or, if you're sure that array a and b will always be of equal length:

p a.map.with_index { |v, i| v + b[i] }
#=> [1, 5, 7, 7, 7]

Upvotes: 7

Related Questions