ruby:对两个或多个数组的相应成员求和

问题描述 投票:0回答:10

我有两个(或更多)数组,每个数组有 12 个整数(对应于每个月的值)。我想要的只是将它们加在一起,这样我就得到了一个包含每个月求和值的数组。这是一个具有三个值的示例: [1,2,3] 和 [4,5,6] => [5,7,9]

我能想到的最好的办法是:

[[1,2,3],[4,5,6]].transpose.map{|arr| arr.inject{|sum, element| sum+element}} #=> [5,7,9]

有更好的方法吗?这似乎是一件很基本的事情。

ruby arrays sum
10个回答
56
投票

这是 Anurag 建议的

transpose
版本:

[[1,2,3], [4,5,6]].transpose.map {|x| x.reduce(:+)}

这适用于任意数量的组件数组。

reduce
inject
是同义词,但
reduce
在我看来更清楚地传达了代码的意图......


18
投票

现在我们可以在2.4中使用sum

nums = [[1, 2, 3], [4, 5, 6]]
nums.transpose.map(&:sum) #=> [5, 7, 9]

11
投票

为了更清晰的语法(不是最快的),您可以使用

Vector
:

require 'matrix'
Vector[1,2,3] + Vector[4,5,6]
=> Vector[5, 7, 9]

对于多个向量,你可以这样做:

arr = [ Vector[1,2,3], Vector[4,5,6], Vector[7,8,9] ]
arr.inject(&:+)
=> Vector[12, 15, 18]

如果您希望将数组加载到向量中并求和:

arrays = [ [1,2,3], [4,5,6], [7,8,9] ]
arrays.map { |a| Vector[*a] }.inject(:+)
=> Vector[12, 15, 18]

8
投票

这是我对代码高尔夫的尝试:

// ruby 1.9 syntax, too bad they didn't add a sum() function afaik
[1,2,3].zip([4,5,6]).map {|a| a.inject(:+)} # [5,7,9]

zip
返回
[1,4]
[2,5]
[3,6]
,map 对每个子数组求和。


8
投票

我谦虚地认为我看到的其他答案非常复杂,以至于会让代码审查者感到困惑。您需要添加解释性注释,这只会增加所需的文本量。

这个怎么样:

a_arr = [1,2,3]
b_arr = [4,5,6]
(0..2).map{ |i| a_arr[i] + b_arr[i] }

稍微不同的解决方案:(这样你就不会硬编码“2”)

a_arr = [1,2,3]
b_arr = [4,5,6]
c_arr = []
a_arr.each_index { |i| c_arr[i] = a_arr[i] + b_arr[i] }

最后,从数学上来说,这与以下问题是相同的:

如何在 Ruby 中执行向量加法?


6
投票
[[1,2,3],[4,5,6]].transpose.map{|a| a.sum} #=> [5,7,9]

1
投票

@FriendFX,您对@user2061694 的回答是正确的。它只适用于我的 Rails 环境。如果进行以下更改,您可以使其在纯 Ruby 中运行...

在IRB

[[0, 0, 0], [2, 2, 1], [1,3,4]].transpose.map {|a| a.inject(:+)}
 => [3, 5, 5]


[[1,2,3],[4,5,6]].transpose.map {|a| a.inject(:+)}
 => [5, 7, 9]

1
投票

对于:

a = [1,2,3]
b = [4,5,6]

您可以

zip
然后使用
reduce
:

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

或者,如果您确定数组

a
b
的长度始终相等:

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

0
投票

这可能不是最好的答案,但它确实有效。

array_one = [1,2,3]
array_two = [4,5,6]
x = 0
array_three = []
while x < array_one.length
  array_three[x] = array_one[x] + array_two[x]
  x += 1
end

=>[5,7,9]

这可能比其他答案有更多的代码行,但它仍然是一个答案


0
投票

只是为了好玩,我对一些可能的解决方案进行了基准测试

# plain-ole
a[0] += b[0]
a[1] += b[1]
a[2] += b[2]
a
# each_index
a.each_index { |i| a[i] += b[i] }
#zip-sum
a.zip(b).map(&:sum)
# transpose-sum
[a, b].transpose.map(&:sum)
#map
a.map.with_index { |v, i| v + b[i] }
# zip-reduce
a.zip(b).map { _1.reduce(&:+) }
# transpose-reduce
[a, b].transpose.map { _1.reduce(&:+) }
# vector-declared
Vector[1, 2, 3] + Vector[4, 5, 6]
# vector
Vector.elements(a) + Vector.elements(b)

使用 Benchmark 并运行各 1,000,000 次,得到以下结果。

Rehearsal ------------------------------------------------------
plain-ole            0.217787   0.000722   0.218509 (  0.218544)
each_index           0.431834   0.001533   0.433367 (  0.433421)
zip-sum              0.576384   0.002875   0.579259 (  0.579365)
transpose-sum        0.588562   0.002788   0.591350 (  0.591382)
map                  0.774294   0.002759   0.777053 (  0.777108)
zip-reduce           1.217026   0.005008   1.222034 (  1.222105)
transpose-reduce     1.244968   0.005115   1.250083 (  1.250596)
vector-initialized   1.691190   0.004128   1.695318 (  1.695422)
vector               1.972912   0.005582   1.978494 (  1.978689)
--------------------------------------------- total: 8.745467sec

                         user     system      total        real
plain-ole            0.215911   0.000831   0.216742 (  0.216781)
each_index           0.430009   0.001125   0.431134 (  0.431200)
zip-sum              0.567621   0.002756   0.570377 (  0.570465)
transpose-sum        0.589709   0.002606   0.592315 (  0.592342)
map                  0.769459   0.002611   0.772070 (  0.772167)
zip-reduce           1.209870   0.004881   1.214751 (  1.214985)
transpose-reduce     1.230031   0.004926   1.234957 (  1.235065)
vector-initialized   1.687652   0.003992   1.691644 (  1.691750)
vector               1.974240   0.005038   1.979278 (  1.979393)
© www.soinside.com 2019 - 2024. All rights reserved.