为什么uniq!如果没有重复则返回 nil

发布于 2024-08-18 16:47:09 字数 909 浏览 3 评论 0原文

我刚刚开始使用 Ruby,我个人认为以下内容违反了“最少意外原则”。也就是说,引用文档,那个uniq! “从 self 中删除重复元素。如果未进行任何更改(即未找到重复项),则返回 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

事实上,我认为这是一个特别严重的错误功能,因为这是一个众所周知的原则,在设计返回数组的方法时,应该始终在至少返回一个空数组,而不是 nil

I'm just starting with Ruby and I personally find the following to be a violation of the "principle of least surprise". And that is, quoting from the documentation, that uniq! "removes duplicate elements from self. Returns nil if no changes are made (that is, no duplicates are found)."

Can anybody explain this, which seems completely counter-intuitive to me? This means that rather than being able to write one line of code below by appending .uniq! to end the first line, I instead have to write the following two lines:

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

Or am I missing something, a better way?

EDIT:

I understand that uniq! modifies its operand. Here's the problem illustrated better I hope:

  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

I contend that the way uniq! works makes it completely senseless and useless. Sure in my case as pointed out I could just append .uniq to the first line. However later in the same program I am pushing elements onto another array inside of a loop. Then, under the loop, I'd like to "de-dupe" the array, but I dare not write 'hooks_tested.uniq!' because it could return nil; instead I must write hooks_tested = hooks_tested.uniq

Indeed I contend this is a particularly egregious mis-feature in that it is a well known principle that, when devising a method that returns an array, one should always at least return an empty array, rather than nil

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

影子的影子 2024-08-25 16:47:09

这是因为 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

If you need to return the value of hook 也许因为它是最后一个方法语句,只需执行即可

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

This is because uniq! modifies self and if uniq! would return a value you wouldn't be able to know whether a change actually occurred in the original object.

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

In your code you can simply write

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

If you need to return the value of hook perhaps because it's the last method statement just do

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

or otherwise

def method
  hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
  hooks.uniq!
  hooks
end
七禾 2024-08-25 16:47:09

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

The exclamation point on uniq! indicates that it modifies the array instead of returning a new one. You should do this:

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

or this

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks.uniq!
puts hooks.length
旧情勿念 2024-08-25 16:47:09

从 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

Since Ruby 1.9, Object#tap is available:

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

And perhaps more succinctly (h/t @Aetherus):

hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).tap(&:uniq!)
puts hooks.length
反目相谮 2024-08-25 16:47:09

您可以将 uniq (末尾没有感叹号)附加到第一行的末尾。

或者,如果您坚持使用 uniq!,请使用

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

You can append uniq (no exclamation mark at the end) to the end of the first line.

Or, if you insist on using uniq!, use

(hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)).uniq!
苍景流年 2024-08-25 16:47:09

这不是原因的答案,而是一种解决方法。

由于 uniq 不返回 nil,因此我使用 uniq 并将结果分配给新变量,而不是使用 bang

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

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

版本变量是一个很小的代价。它肯定比执行 if 检查要好得多,重复复杂的调用 uniq!uniq 并检查 nil

This is not an answer to why, but rather, a workaround.

Since uniq doesn't return nil, I use uniq and assign the the result to a new variable instead of using the bang version

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

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

Having a new variable is a small price to pay. It sure as hell beats doing if checks, with repeated complex calls to uniq! and uniq and checking for nil

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文