2010-01-20 43 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 
相关问题