2011-03-01 154 views
51
(1..4).collect do |x| 
    next if x == 3 
    x + 1 
end # => [2, 3, nil, 5] 
    # desired => [2, 3, 5] 

如果next條件滿足,collect提出nil在陣列中,而我想要做的就是把沒有元素返回數組中如果條件滿足。這可能不會在返回的數組上調用delete_if { |x| x == nil }跳過迭代收集

(使用Ruby 1.8.7;我的代碼摘錄在很大程度上抽象)

回答

74

有方法Enumerable#reject供應只是目的:

(1..4).reject{|x| x == 3}.collect{|x| x + 1} 

直接使用一種方法的輸出作爲另一個輸入的做法被稱爲方法鏈式,是非常在Ruby中很常見。

順便說一句,map(或collect)用於輸入enumerable直接映射到輸出。如果您需要輸出不同數量的元素,則可能需要使用另一種方法Enumerable

編輯:如果你是一個事實,即某些元素被重複兩次困擾,您可以使用基於較少優雅的解決方案inject(或其類似方法命名each_with_object):

(1..4).each_with_object([]){|x,a| a << x + 1 unless x == 3} 
+3

美麗的代碼。這比我的解決方案好得多。 – Benson 2011-03-01 09:23:35

+3

這是最慢的答案(雖然不是太多),但肯定是最乾淨的。我只是希望有一種方法可以用'collect'做到這一點,因爲我期望調用'next'返回_absolutely nothing_,而不是「nothing」(又名'nil')。 – 2011-03-01 23:12:54

+1

如果比其他任何方法都慢,那麼Ruby的優化器可能會使用一些您認爲沒有用的工作? – Shannon 2012-12-27 21:30:00

44

我會簡單地調用.compact所得陣列,這消除零的任何實例中的陣列上。如果你想它修改現有的陣列(沒有理由不),使用.compact!

(1..4).collect do |x| 
    next if x == 3 
    x 
end.compact! 
+13

我做了一個快速基準,利息,這四個解決方案的建議至今:收集+壓縮,收集+緊湊!拒絕+收集並將結果數組構建爲y你去吧。在MRI 1.9.1中,至少收集+緊湊!是一個狹窄的優勢,收集+緊湊和拒絕+收集在後面很接近。建立結果數組的速度大約是那些速度的兩倍。 – 2011-03-01 14:01:18

+0

@glenn:你介意在你的基準測試中包括以下內容:'(1..4).inject([]){| a,x | x == 3? a:a.push(x + 1)}?謝謝。 – 2011-03-01 14:59:51

+0

當然。這是最慢的一個,雖然只比構建結果數組稍慢一點。我還添加了一個像這樣調整的版本:'a.inject([]){| aa,x | aa << x + 1,除非x == 3; aa}',這比構建陣列要快,但仍然比三種快速方法慢得多。 – 2011-03-01 18:07:55

0

我會建議使用:

(1..4).to_a.delete_if {|x| x == 3} 

,而不是收集+下一條語句。

+0

_real_代碼比我的問題中的抽象代碼更復雜,所以這不會實現我正在尋找的東西,不幸的是。 (該收集實際上操縱的價值,而不是僅僅返回它) – 2011-03-01 08:53:39

+0

好吧,所以建議的契約!解決方案就是你的選擇。 – ALoR 2011-03-01 08:55:36

4

只是一個建議,你爲什麼不這樣做:

result = [] 
(1..4).each do |x| 
    next if x == 3 
    result << x 
end 
result # => [1, 2, 4] 

以這種方式保存的另一次迭代,除去從零數組元素。希望它有助於=)

+0

這就像Mladen的「拒絕」示例的更詳細的版本。 – Benson 2011-03-01 09:22:16

+0

實際上是nope,「reject」一次遍歷數組,並且「collect」再次遍歷數組,因此有兩個迭代。在「每個」的情況下,它只做一次=) – Staelen 2011-03-01 09:27:27

+4

這是一個合理的想法,但在Ruby中,進行速度測試並查看實際發生的事情通常非常有趣。在我的快速基準測試中(當然這可能與安德魯的實際情況相匹配),以這種方式構建陣列的速度實際上是其他任何方式的兩倍。我懷疑問題是在C中迭代數組實際上要比在Ruby <<級別追加項目要快得多。 – 2011-03-01 14:04:28

0

你可以拉決策變成一個輔助方法,並用它通過Enumerable#reduce

def potentially_keep(list, i) 
    if i === 3 
    list 
    else 
    list.push i 
    end 
end 
# => :potentially_keep 

(1..4).reduce([]) { |memo, i| potentially_keep(memo, i) } 
# => [1, 2, 4]