2010-01-20 91 views
11

我剛剛開始使用Ruby,並且我個人發現以下內容違反了「最少突擊原則」。那就是從the documentation引用那個uniq! 「從自身中刪除重複的元素,如果沒有更改,則返回nil(即沒有找到重複項)。」爲什麼uniq!如果沒有重複項,則返回nil

有人可以解釋這一點,這似乎完全違反我的直覺?這意味着,不能通過追加.uniq來編寫下面的一行代碼!要結束第一行,我必須寫下面兩行:

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/) 
    hooks = hooks.uniq 

或者我錯過了什麼,更好的方法?

編輯:

我明白,uniq!修改其操作數。這裏的問題說明更好,我希望:

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/) 
    puts hooks.length #50 
    puts hooks.uniq!.length #undefined method `length' for nil:NilClass 

我爭辯說uniq!作品使它完全沒有意義而且毫無用處。正如我指出的那樣,我可以在第一行添加.uniq。然而,後來在同一個程序中,我將元素推送到循環內的另一個數組上。然後,在循環中,我想「重複」數組,但我不敢寫'hooks_tested.uniq!'因爲它可能返回零;代替我必須寫入hooks_tested = hooks_tested.uniq

事實上,我抗衡這是一個特別嚴重的錯誤特徵在於它是一個公知的原則,即,制訂對返回一個數組,要時常的方法時至少返回一個空數組,而不是零

+3

的POLS有紅寶石特定的含義:「並不感到意外馬茨(Ruby的創建者) – 2010-01-20 15:22:19

+0

無用的(不正確)的用途時,你試圖把它同意方便,如果。你正在嘗試做些什麼 - 例如 - 測試'uniq!'的結果。這可能是馬茨想到的。 ;-) – 2010-01-20 17:26:55

+0

我同意。這是非常類似PHP的(隨機的,不協調的例外情況)。所有其他情況下,包括'uniq'都會返回原來的情況。當'uniq'找不到重複項時,它會返回數組本身。嚴重跆拳道。 – ahnbizcad 2016-09-07 21:45:44

回答

10

這是因爲uniq!修改self如果uniq!會返回一個值,你將無法知道改變是否真正發生在原目的。

var = %w(green green yellow) 
if var.uniq! 
    # the array contained duplicate entries 
else 
    # nothing changed 
end 

在你的代碼,你可以簡單地寫

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/) 
hooks.uniq! 
# here hooks is already changed 

如果您需要返回鉤或許的價值,因爲它是最後的方法聲明只是做

def method 
    hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/) 
    hooks.uniq 
end 

或以其他方式

def method 
    hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/) 
    hooks.uniq! 
    hooks 
end 
+0

「感嘆號」方法的返回值通常是任意的,因爲它們就地修改對象。這種情況不幸的是它創造的一些語義混亂,如你的例子所示:如果uniq!那麼......實際上不是唯一的。 – tadman 2010-01-20 15:53:17

2

您可以在第一行的末尾追加uniq(末尾沒有感嘆號)。

或者,如果你堅持要用uniq!,使用

(hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)).uniq! 
+0

是的,我想我可以在這種情況下 – 2010-01-20 15:04:49

5

的感嘆號uniq!表明它會修改數組,而不是返回一個新的。你應該這樣做:

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).uniq 

或本

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/) 
hooks.uniq! 
puts hooks.length 
+1

通常,如果您使用方法的爆炸形式,它將是唯一的方法特定對象(即不在鏈中)。這部分是爲了消除諸如'hooks = hooks.uniq!.sort'或'hooks.uniq!.sort!'這樣的含糊不清的語句(您可以在同一個表達式中擁有相同變量的多個賦值)或者分配給中間臨時值,例如'hooks.uniq.sort!'。 'Array.uniq!'還會返回'nil'而不是'[]',因此您可以執行諸如「if(hooks.uniq!)'來修改數組並在發生任何更改時執行特殊操作。 – bta 2010-01-20 17:27:51

+0

對於nil:NilClass,如果它的掛鉤不包含重複項,則第二個建議結果爲「未定義的方法長度」 - 這正是我想要引起注意的意外行爲,但顯然它不合邏輯 - 呃,耳聾 - 耳朵 – 2010-01-20 17:37:47

+0

好的,對不起。如果第二個例子不起作用,這裏還有其他的事情要做。你使用的是什麼版本的Ruby? – mckeed 2010-01-20 18:01:05

0

這不是解決問題的答案,而是解決方法。

由於uniq不返回nil,我用uniq和結果分配給一個新的變量,而不是使用爆炸版本

original = [1,2,3,4] 
new = original.uniq 

#=> new is [1,2,3,4] 
#=> ... rather than nil 

有一個新的變量是一個很小的代價的。它肯定是地獄的節拍做的,如果檢查,反覆複雜調用uniq!uniq和檢查nil

1

由於Ruby 1.9的,Object#tap可用:

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).tap do |hooks| 
    hooks.uniq! 
end 
puts hooks.length 

也許更簡潔(H/T @Aetherus ):

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).tap(&:uniq!) 
puts hooks.length 
相關問題