我们采取以下数组:
[1, 4, 5, 3, 1, 4, 6, 5, 4]
它具有以下转折点(当上升变化为下降时,反之亦然):
使任务更加通用:
a = [a1, a2, ...]
p(x,y) -> z
,其中z
为Comparable
我想写一些像:
a.detect_edges{|prev, n| prev >= n} # => [[5,2], [1, 4], [6,6]]
使用各自的索引获得转折点的最优雅方法是什么?这是我的代码,从美学的角度来看,我不满意:
class Array
def detect_edges(&blk)
return nil if self.length < 2
prev = blk.call(self[0], self[1])
result = []
self[0..-2].each_with_index do |elem, i|
current = blk.call(elem, self[i+1])
if current != prev
result.push [elem, i]
end
prev = current
end
result
end
end
答案 0 :(得分:5)
[1, 4, 5, 3, 1, 4, 6, 5, 4]
.each_cons(3).with_index(1)
.reject{|(e1, e2, e3), i| (e1 <=> e2) == (e2 <=> e3)}
.map{|(e1, e2, e3), i| [e2, i]}
# => [[5, 2], [1, 4], [6, 6]]
答案 1 :(得分:4)
看看,没有map
!
a = [1, 4, 5, 3, 1, 4, 6, 5, 4]
a[1..-2].each.with_index(1).reject { |e,i| (a[i-1]<=>e) == e<=>a[i+1] }
#=> [[5, 2], [1, 4], [6, 6]]
答案 2 :(得分:2)
所以你基本上想要元素及其索引,其中元素是1索引范围内的局部最大值:
arr.each.with_index.select { |element, index| element == arr[index.pred..index.next].max }
# => [[5, 2], [6, 6]]
注意,您必须处理第一个元素的情况或元素是否相等。
<小时/> 编辑:对于您的更新版本,您只需检查<=>
的结果是否已更改。请注意,当元素相等时,您将再次检查案例:
arr.each.with_index.to_a.tap(&:pop).drop(1).select do |element, index|
(arr[index.pred] <=> element) != (element <=> arr[index.next])
end # => [[5, 2], [1, 4], [6, 6]]
答案 3 :(得分:2)
我没有理由得到更多的幻想:
class Array
def detect_edges
self.collect.with_index do |e, i|
next if i == 0 || i >= size-1
yield(self[i-1],e) != yield(e,self[i+1]) ? [e, i] : nil
end.compact
end
end
请注意,在修补Array
时,应该使用优化。