如何在Array#delete_if中引用元素的索引

我想构建一个自定义方法Array#drop_every(n) (我知道它是猴子修补,我这是为了做作业),它返回一个新的数组,省略了每个第n个元素:

 [4, 8, 15, 16, 23, 42].drop_every(2) # [4, 15, 23] 

我想用Array#delete_if来实现它,但是通过引用索引而不是元素本身,(类似于each_index )是这样的:

 def drop_every(step) self.delete_if { |index| index % step == 0 } end 

我该怎么做呢? 我不坚持使用delete_if ,我也看了drop_whilereject ,欢迎其他建议。

 def drop_every(step) reject.with_index { |x,i| (i+1) % step == 0 } end [4, 8, 15, 16, 23, 42].reject.with_index{|x,i| (i+1) % 2 == 0} # => [4, 15, 23] [4, 8, 15, 16, 23, 42].reject.with_index{|x,i| (i+1) % 3 == 0} # => [4, 8, 16, 23] 

您可以使用返回枚举器的with_index方法,过滤您的集合,然后删除索引。

 class Array def drop_every(step) self.each.with_index.select { |_, index| index % step == 0 }.map(&:first) end end [4, 8, 15, 16, 23, 42].drop_every(2) # => [4, 15, 23] 

您可以使用values_at方法有选择地筛选出所需的索引。

 class Array def drop_every(step) self.values_at(*(0...self.size).find_all{ |x| (x+1) % step != 0 }) end end 

在我输入时,答案被接受了。 无论如何我会发布它。

 def drop_every step delete_if.with_index(1){|_, i| i.%(step).zero?} end 
 class Array def drop_every(step) self.each_slice(step).flat_map{|slice| slice[0..-2]} end end p [4, 8, 15, 16, 23, 42].drop_every(2) #=> [4, 15, 23] 

我将扩展Enumerable mixin:

 module Enumerable def drop_every(step) return to_enum(:drop_every, step) unless block_given? each.with_index(1) do |o, i| yield o unless i % step == 0 end end end (1..10).drop_every(3) { |a| pa } # outputs below 1 2 4 5 7 8 10