Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get an array of maximum values between two arrays

Tags:

ruby

I'm looking for an elegant way of getting an array containing the maximum values between two arrays.

Meaning if there are two arrays:

a = [1, 5, 9]
b = [3, 2, 11]

The result should be:

=> [3, 5, 11]

Assume both arrays are of the same size.

The code I use doesn't feel like a Ruby way to do that task:

c = Array.new(a.size)
for i in 0...a.size
  c[i] = [a[i], b[i]].max
end
like image 576
miluz Avatar asked Sep 11 '13 14:09

miluz


1 Answers

This should work:

[a, b].transpose.map(&:max)
#=> [3, 5, 11]

transpose returns [[1, 3], [5, 2], [9, 11]] and map(&:max) finds each sub array's maximum.

a.zip(b) (as suggested by Abe Voelker) is equivalent to [a, b].transpose if both arrays have the same number of elements. If element size differs, transpose would raise an exception:

[1].zip([2,3])
#=> [[1,2]]

[[1], [2,3]].transpose
#=> IndexError: element size differs

Benchmarks

require 'benchmark'

a = (1..1000).to_a
b = a.reverse

n = 1000
Benchmark.bm(10) do |x|
  x.report("transpose")  { n.times { [a,b].transpose.map(&:max) } }
  x.report("zip")        { n.times { a.zip(b).map(&:max) } }
  x.report("lazy.zip")   { n.times { a.lazy.zip(b).map(&:max).to_a } }
  x.report("loop (max)") { n.times { a.size.times.map{|i| [a[i],b[i]].max} } }
  x.report("loop (>?:)") { n.times { a.size.times.map{|i| a[i]>b[i] ? a[i] : b[i] } } }
end

Output

                 user     system      total        real
transpose    0.430000   0.000000   0.430000 (  0.428760)
zip          0.420000   0.000000   0.420000 (  0.415070)
lazy.zip     1.010000   0.000000   1.010000 (  1.009173)
loop (max)   0.490000   0.000000   0.490000 (  0.489015)
loop (>?:)   0.150000   0.000000   0.150000 (  0.151461)
like image 52
Stefan Avatar answered Oct 03 '22 18:10

Stefan