views:

124

answers:

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"}]
+3  A: 

It already works for me in 1.8.7.

1:~$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
1:~$ irb -v
irb 0.9.5(05/04/13)
1:~$ irb
>> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq 
=> [{"three"=>"3"}, {"three"=>"4"}]
DigitalRoss
lol, then we have to update. Thanks!
khelll
+1  A: 

How about this?

h={}
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].select {|e| need=!h.key?(e) ; h[e]=1 ; need} 
#=> [{"three"=>"3"}, {"three"=>"4"}]
pierr
This is very customized one, I wanted a general solution that considers object equality.
khelll
+1  A: 

I've run into this myself many times. Hash equality in Ruby 1.8.6 is broken:

require 'test/unit'

class TestHashEquality < Test::Unit::TestCase
  def test_that_an_empty_Hash_is_equal_to_another_empty_Hash
    assert({}.eql?({}), 'Empty Hashes should be eql.')
  end
end

Passes in Ruby 1.9 and Ruby 1.8.7, fails in Ruby 1.8.6.

Jörg W Mittag
+2  A: 

The problem is that Hash#hash and Hash#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:

class Hash
  if {}.hash != {}.hash
    def hash
      # code goes here
    end
  end
  if !{}.eql?({})
    def eql?(other)
      # code goes here
    end
  end
end

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.

Bob Aman
Bob, if you do this regularly, I'd love to see what you put in those methods. I wonder if it would make a good candidate for submission to the backports gem?
dkubb
I should note that the backports project has added a work-around for this issue: http://github.com/marcandre/backports/commit/10ba02021751e2eb6ce671fd558a9acea9037ade
dkubb
To be honest, I like their implementation of `# code goes here` better.
Bob Aman