扩展 uniq 方法
这是 Ruby 1.8 问题:
我们都知道如何使用 Array#uniq
:
[1,2,3,1].uniq #=> [1,2,3]
但是我想知道我们是否可以以一种处理复杂对象的方式对其进行猴子修补。当前的行为是这样的:
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
#=> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}]
请求的行为是:
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
#=> [{"three"=>"3"}, {"three"=>"4"}]
This is Ruby 1.8 Question:
We all know how to use Array#uniq
:
[1,2,3,1].uniq #=> [1,2,3]
However I'm wondering if we can monkey patch it in a way to work with complex objects. The current behavior is like this:
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
#=> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}]
The requested one is:
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
#=> [{"three"=>"3"}, {"three"=>"4"}]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我自己也多次遇到过这种情况。 Ruby 1.8.6 中的哈希相等性被破坏:
在 Ruby 1.9 和 Ruby 1.8.7 中通过,在 Ruby 1.8.6 中失败。
I've run into this myself many times. Hash equality in Ruby 1.8.6 is broken:
Passes in Ruby 1.9 and Ruby 1.8.7, fails in Ruby 1.8.6.
类似的事情怎么样?只是通过块的哈希值或哈希键进行 uniq_by 。
How about something like that? just uniq_by the hash value or hash key via the block.
要使 Array#uniq 适用于任何对象,您必须重写两个方法:hash 和 eql?
所有对象都有一个哈希方法来计算该对象的哈希值,因此要使两个对象相等,它们的哈希值也必须相等。
示例 - 当用户的电子邮件地址唯一时,该用户也是唯一的:
To make Array#uniq work for any object you must override two methods: hash and eql?
All objects have a hash method which calculates the hash value for that object, so for two objects to be equal their values when hashed must also be equal.
Example--a user is unique when their email address is unique:
它在 1.8.7 中已经对我有用了。
It already works for me in 1.8.7.
问题是
Hash#hash
和Hash#eql?
在 Ruby 1.8.6 中都给出了虚假结果。这是我愿意执行的非常罕见的猴子补丁之一,因为这个错误严重破坏了很多代码——特别是记忆功能。只是要小心猴子补丁,不要覆盖未损坏的行为。所以:
但是,如果您正在执行控制部署环境的操作,则只需在应用程序从 1.8.6 开始时引发错误即可。
The problem is that
Hash#hash
andHash#eql?
both give bogus results in Ruby 1.8.6. This is one of the very rare monkey patches I've been willing to perform, because this bug seriously breaks a lot of code — in particular memoizing functions. Just be careful with monkey patches that you don't override non-broken behavior.So:
But if you're doing something where you control the deploy environment, just raise an error if the app gets started with 1.8.6.
这个怎么样?
How about this?