问题
I want to build a custom method Array#drop_every(n) (I know it's monkey patching, I am doing this for a homework), which returns a new array omitting every nth element:
[4, 8, 15, 16, 23, 42].drop_every(2) # [4, 15, 23]
I want to implement it with Array#delete_if, but by referring to the index and not to the element itself, (similar to each_index) something like this:
def drop_every(step)
self.delete_if { |index| index % step == 0 }
end
How do I do this? I don't insist on using delete_if, I also looked at drop_while and reject, other suggestions are welcome.
回答1:
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:
You can use with_index method that returns enumerator, filter your collection and then get rid of the indexes.
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]
回答3:
You could use the values_at method to selectively filter out indices which you want.
class Array
def drop_every(step)
self.values_at(*(0...self.size).find_all{ |x| (x+1) % step != 0 })
end
end
The answer was accepted while I was typing it. I will post it anyways.
回答4:
def drop_every step
delete_if.with_index(1){|_, i| i.%(step).zero?}
end
回答5:
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]
回答6:
I'd extend the Enumerable mixin instead:
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
来源:https://stackoverflow.com/questions/19317782/how-to-refer-the-index-of-an-element-in-arraydelete-if