根据我对折叠如何工作的理解,给出一个整数数组和一些现有值(比如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
有没有更好的方法来写这个?
答案 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
低效?是的,但只需很少的费用就能让它读得很好。