6

我正在寻找一种优雅的方式来获取包含两个数组之间最大值的数组。

意思是如果有两个数组:

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

结果应该是:

=> [3, 5, 11]

假设两个数组的大小相同。

我使用的代码感觉不像是完成该任务的 Ruby 方式:

c = Array.new(a.size)
for i in 0...a.size
  c[i] = [a[i], b[i]].max
end
4

3 回答 3

14

这应该有效:

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

transpose返回[[1, 3], [5, 2], [9, 11]]map(&:max)找到每个子数组的最大值。

a.zip(b)(如 Abe Voelker 所建议的那样)等效于[a, b].transpose两个数组是否具有相同数量的元素。如果元素大小不同,transpose将引发异常:

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

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

基准

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

输出

                 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)
于 2013-09-11T14:48:43.540 回答
7
a.zip(b).map(&:max) # => [3, 5, 11]
于 2013-09-11T14:49:53.157 回答
4

下面怎么样?

注意:大小应该等于两个数组。

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

p a.size.times.map{|i| [a[i],b[i]].max}
# >> [3, 5, 11]

或者

a = [1, 5, 9]
b = [3, 2,11]
p a.size.times.map{|i| a[i]>b[i] ? a[i] : b[i] }
# >> [3, 5, 11]

或者,

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

p a.each_index.map{|i| a[i]>b[i] ? a[i] : b[i] }
# >> [3, 5, 11]

基准

require 'benchmark'

iterations = 10_000

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

def stefan(a,b)
  [a, b].transpose.map(&:max)
end

def abe(a,b)
  a.zip(b).map(&:max)
end

def babai1(a,b)
  a.size.times.map{|i| a[i]>b[i] ? a[i] : b[i] }
end

def babai2(a,b)
  a.size.times.map{|i| [a[i],b[i]].max}
end

def babai3(a,b)
  a.each_index.map{|i| a[i]>b[i] ? a[i] : b[i] }
end

Benchmark.bm do |bm|
  bm.report('Stefan') do
    iterations.times do
      stefan(a,b)
    end
  end

  bm.report('Abe') do
    iterations.times do
      abe(a,b)
    end
  end

  bm.report('babai1') do
    iterations.times do
      babai1(a,b)
    end
  end

  bm.report('babai2') do
    iterations.times do
      babai2(a,b)
    end
  end
  bm.report('babai3') do
    iterations.times do
      babai3(a,b)
    end
  end
end

输出

    user     system      total        real
Stefan  0.047000   0.000000   0.047000 (  0.046874)
Abe     0.047000   0.000000   0.047000 (  0.046873)
babai1  0.031000   0.000000   0.031000 (  0.031249)
babai2  0.062000   0.000000   0.062000 (  0.062497)
babai3  0.032000   0.000000   0.032000 (  0.031249)
于 2013-09-11T15:01:10.273 回答