使用inject总结整数数组数组的每个其他数组

时间:2015-01-15 16:55:44

标签: ruby arrays fold

根据我对折叠如何工作的理解,给出一个整数数组和一些现有值(比如2)

val = 2
arr = [1,2,3]

我可以说

arr.inject(val) do |r, val|
  r += val
end

以特定顺序(从左到右?)将所有元素添加到指定值。

所以现在如果我有一个像这样的整数数组

val = 2
arr = [ [1], [2], [3] ]

我的逻辑很相似,除了我现在有一层额外的数组:

val = arr.inject(val) do |r, arrElmt|
  r = arrElmt.inject(r, :+)
end

但是现在我只希望每个其他元素都以第一个元素开头,所以我想忽略[2],只需加上1和3。

我不知道怎么用折叠做这个,所以我最终回到使用类似each_with_index的东西,然后跳过奇数索引。

val = 2
arr = [ [1], [2], [3] ]

arr.each_with_index do |arrElmt, i|
  next if i.odd?
  val = arrElmt.inject(val, :+)
end

有没有更好的方法来写这个?

4 个答案:

答案 0 :(得分:3)

如果内部数组只是一个元素,则可以先展平。可能有十几种方法可以在Ruby中完成这一切,其中许多方面看起来有点钝,但是这是另一种:

val += arr.flatten.values_at(* arr.each_index.select(&:even?)).reduce(:+)

这会将奇数值相加,并将结果添加到val。使用even?方法,它看起来可能看起来不正确,但这是因为Ruby数组基于0索引。

答案 1 :(得分:2)

你可以这样做:

val = arr.each_slice(2).inject(val) do |total, (even, _odd)|
   even.inject(total, :+)
end

each_slice(n)一次产生n个项目。在这种情况下,它将首先产生第一个&第二项,然后是第三项和第四项,依此类推。然后我只在总和中使用每个对中的第一个元素。如果您想对奇数指数求和,那么您只需将pair[0]更改为pair[1] || []

那就是说,你可能会说你原来的尝试更清楚了。

答案 2 :(得分:2)

以下是参数解析绑定的一些乐趣:

arr.each_slice(2).inject(val) {|acc, ((el, *_), _)| acc + el }

更严肃的方法是:

arr.each_slice(2).inject(val) {|acc, (el, _)| acc.+(*el) }

arr.each_slice(2).inject(val) {|acc, (el, _)| acc + el.first }

更接近原来的尝试:

arr.each_with_index.inject(val) {|acc, (el, i)|
  if i.odd? then acc else acc + el.first end }

答案 3 :(得分:2)

另一种方式:

def sum_even_elements(arr)
  arr.each_slice(2).map(&:first).flatten.reduce(:+)
end

sum_even_elements([1,2,3,4,5])                     #=> 9 
sum_even_elements([[1],[2],[3],[4],[5]])           #=> 9 
sum_even_elements([[1,2],[3,4],[5,6],[7,8],[9,0]]) #=> 23

如果需要:

def sum_odd_elements(arr)
  arr.flatten.reduce(:+) - sum_even_elements(arr)
end

低效?是的,但只需很少的费用就能让它读得很好。