2013-10-11 39 views
2

我想構建一個自定義方法Array#drop_every(n)(我知道它是猴子補丁,我正在做這個作業),它返回一個新的數組忽略每個第n個元素:如何引用Array中的一個元素的索引#delete_if

[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,歡迎提出其他建議。

+1

一定要看到更新的答案,一個之前沒有爲步工作> 2 – tihom

回答

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] 
+0

我喜歡的短簡潔的解決方案,但該方法返回正好與我想要的相反 - 它返回每第n個元素,我希望它忽略每個第n個元素。 –

+0

updated..was不知道你想要哪一個 – tihom

+0

@AlexPopov通過解決方案更改爲最終得到你的意思...前一個不適用於步驟超過2 – tihom

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] 
2

你可以使用values_at方法選擇性地過濾出您想要索引。

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

答案在我輸入時被接受。無論如何,我會發布它。

+0

使用'self.size -1'否則它將返回在某些情況下,最後一個元素爲'nil'。 – tihom

+0

@tihom我用'...'(半開間隔) – bsd

+0

很好..不知道那個語法...我的壞 – tihom

1
def drop_every step 
    delete_if.with_index(1){|_, i| i.%(step).zero?} 
end 
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] 
1

我會延長Enumerable混入代替:

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 
相關問題