2015-08-28 31 views
1

拒絕有沒有一種合理的方式來做到以下幾點:破壞性從數組返回值拒絕

我要帶一個數組,然後從根據條件陣列的具體項目,從數組刪除他們,他們走。 (我基本上想要將數組的內容分成不同的類別)。

array = [1,2,3,4,5,6,7,8] 

less_than_three = array.reject_destructively{|v| v<3} 
=> [1,2] 
array 
=> [3,4,5,6,7,8] 
more_than_five = array.reject_destructively{|v| v>5} 
=> [6,7,8] 
array 
=> [3,4,5] 

我試過delete_if,選擇!,拒絕!並且他們中沒有一個似乎能夠給你受影響的物品,而剩下的則是陣列。 除非我生氣,這是完全可能的。

回答

5

你可以建立自己的這種方法...

class Array 
    def extract(&block) 
    temp = self.select(&block) 
    self.reject!(&block) 
    temp 
    end 
end 

然後...

a = [1, 2, 3, 4, 5] 
a.extract{|x| x < 3} 
=> [1,2] 
p a 
=> [3, 4, 5] 

編輯:如果你不想猴子補丁(但猴子修補本身並不是邪惡的),你可以用香草方法做到這一點...

def select_from_array(array, &block) 
    temp = array.select(&block) 
    array.reject!(&block) 
    temp 
end 

array = [1,2,3,4,5,6,7,8] 

less_than_three = select_from_array(array){|v| v<3} 
=> [1,2] 
array 
=> [3,4,5,6,7,8] 
more_than_five = select_from_array(array){|v| v>5} 
=> [6,7,8] 
array 
=> [3,4,5] 
+0

寧願避免猴子補丁,如果我可以......這看起來像它確實需要什麼,但我只知道我會打破某些東西,忘記我做了什麼...... – Carpela

+0

好吧,編輯,以避免猴子補丁:) – SteveTurczyn

0

這樣做是否有助於

class Array 
    def reject_destructively(&block) 
     arr = self.select(&block) 
     arr.each{ |i| self.delete(i) } 
     arr 
    end 
end 

array = [1,2,3,4,5,6,7,8] 
p less_than_three = array.reject_destructively{|v| v<3} 
#=> [1,2] 
p array 
#=> [3,4,5,6,7,8] 
p more_than_five = array.reject_destructively{|v| v>5} 
#=> [6,7,8] 
p array 
#=> [3,4,5] 

上面的代碼可以進一步簡化的樣子:

class Array 
    def reject_destructively(&block) 
     self.select(&block).each{ |i| self.delete(i) } 
    end 
end 
+0

有同樣的問題。少於三則返回[3,4,5,6,7,8](這當然與我們所需要的完全相反) – Carpela

+1

好的更新答案 - 我正在使用猴子補丁 –

0
irb(main):001:0> array = [1,2,3,4,5,6,7,8] 
=> [1, 2, 3, 4, 5, 6, 7, 8] 
irb(main):002:0> array.partition{|v| v < 3} 
=> [[1, 2], [3, 4, 5, 6, 7, 8]] 

是有什麼具體原因,爲什麼這必須是destructive

-1

您可以使用group_by獲取滿足一個組中所有條件的所有元素,其餘所有元素都可以使用。 例如

[1,2,3,4,5].group_by{|i| i > 3} 

{false=>[1, 2, 3], true=>[4, 5]} 

更多信息,請http://ruby-doc.org/core-2.1.1/Enumerable.html#method-i-group_by

+0

可能沒有一個很好的方法來做到這一點,但我需要從數組中提取第一個「組」,然後再提取一個後來的組,因爲有些項目會成爲我只想在第一個組中的共享成員...... – Carpela

+1

這就是分區的用途:'(1..6).partition {| v | v.even?}#=> [[2,4,6],[1,3,5]]' –

+0

感謝那個axel,我沒有意識到那個函數,但是在這種情況下它更簡單。 – JHobern

3

我的理解這個問題,你不想產生兩個新的對象。這裏你去:

class Array 
    def carve! 
    dup.tap { delete_if &Proc.new } - self 
    end 
end 

array = [1,2,3,4,5,6,7,8] 
p array.carve! { |v| v < 3 } 
#⇒ [1, 2]     # returned by Array#carve method 
p array 
#⇒ [3, 4, 5, 6, 7, 8]  # remained in original array 

使用此解決方案,array.__id__保持不變。這是最好的答案:)

0

好的。這工作,避免猴子補丁,它使一個行...等,但它是該死的醜陋....

less_than_three = array.dup - array.reject!{|v| v<3} 
=> [1,2] 
array 
=> [3,4,5,6,7,8] 
more_than_five = array.dup - array.reject!{|v| v>5} 
=> [6,7,8] 
array 
=> [3,4,5] 
+0

monkeypatching有什麼問題? – mudasobwa

+0

沒什麼,如果你知道你在做什麼,我想。我只是總是有點警惕...... – Carpela

0
module Enumerable 
    def reject_destructively 
     array=[] 
     self.each do |y| 
      if yield(y) 
       array<<y 
      end 
     end 
     array.each do |x| 
      self.delete(x) 
     end 
     return array 
    end 
end 
array=[10,9,2,1,3,45,52] 
print less_than_three = array.reject_destructively{|v| v < 3} 
print array