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

时间:2013-10-11 12:08:00

标签: ruby methods

我想构建一个自定义方法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,欢迎提出其他建议。

6 个答案:

答案 0 :(得分:3)

您可以使用返回枚举器的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]

答案 1 :(得分:2)

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] 

答案 2 :(得分:2)

您可以使用values_at方法有选择地过滤掉您想要的索引。

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

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

答案 3 :(得分:1)

def drop_every step
  delete_if.with_index(1){|_, i| i.%(step).zero?}
end

答案 4 :(得分:1)

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]

答案 5 :(得分:1)

我会扩展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| p a }
# outputs below
1
2
4
5
7
8
10