Uniq() Oddity

Would someone please explain this behavior to me?

   a = [ { :foo => :bar }, { :foo => :bar } ]

   p a #=> [{:foo=>:bar}, {:foo=>:bar}]
   p a[0] == a[1] #=> true
   # why does this next call do nothing?
   p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

   # inefficient work-around
   p a.inject([]) { |cp, e| cp.include?(e) ? cp : cp << e } #=> [{:foo=>:bar}]

James Edward Gray II

Seems to compare on object id, rather than with ==. I couldn't speculate on any more significant answer to 'why?'

a[0].id == a[1].id
=> true

b = [a[0], a[0]]
b.uniq
=> [{:foo=>:bar}]

matthew smillie.

···

On Jun 20, 2006, at 15:17, James Edward Gray II wrote:

  a = [ { :foo => :bar }, { :foo => :bar } ]

  p a #=> [{:foo=>:bar}, {:foo=>:bar}]
  p a[0] == a[1] #=> true
  # why does this next call do nothing?
  p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

From: James Edward Gray II [mailto:james@grayproductions.net]
Sent: Tuesday, June 20, 2006 4:17 PM

Would someone please explain this behavior to me?

   a = [ { :foo => :bar }, { :foo => :bar } ]

   p a #=> [{:foo=>:bar}, {:foo=>:bar}]
   p a[0] == a[1] #=> true
   # why does this next call do nothing?
   p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

   # inefficient work-around
   p a.inject() { |cp, e| cp.include?(e) ? cp : cp << e } #=>
[{:foo=>:bar}]

James Edward Gray II

a = [ { :foo => :bar }, { :foo => :bar } ]

class Hash
    def hash
        self.to_a.sort.hash
    end
    
    def eql? other
        size == other.size && keys.all?{|k| self[k] == other[k]}
    end
end

p a.uniq #=> [{:foo=>:bar}]

hth

Simon

   p a[0] == a[1] #=> true
   # why does this next call do nothing?
   p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

#uniq first create an hash : this mean that it don't use #== for the
comparison.

moulon% ruby -e 'a = [{:f =>:b}, {:f => :b}]; p a[0].eql?(a[1]); p a[0]==a[1]'
false
true
moulon%

Guy Decoux

Doesn't seem to work for hashes at all:
irb(main):005:0> [{}, {}].uniq
=> [{}, {}]

Yet:
irb(main):008:0> {} == {}
=> true

···

On 6/20/06, James Edward Gray II <james@grayproductions.net> wrote:

Would someone please explain this behavior to me?

   a = [ { :foo => :bar }, { :foo => :bar } ]

   p a #=> [{:foo=>:bar}, {:foo=>:bar}]
   p a[0] == a[1] #=> true
   # why does this next call do nothing?
   p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

   # inefficient work-around
   p a.inject() { |cp, e| cp.include?(e) ? cp : cp << e } #=>
[{:foo=>:bar}]

James Edward Gray II

Can any body help me with How to "unsubscribe" from the ruby talk
mailing list.

Thanks.

  a = [ { :foo => :bar }, { :foo => :bar } ]

  p a #=> [{:foo=>:bar}, {:foo=>:bar}]
  p a[0] == a[1] #=> true
  # why does this next call do nothing?
  p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

Seems to compare on object id, rather than with ==.

Can't be that:

>> str1 = "a"
=> "a"
>> str2 = "a"
=> "a"
>> str1.object_id == str2.object_id
=> false
>> [str1, str2].uniq
=> ["a"]

James Edward Gray II

···

On Jun 20, 2006, at 9:25 AM, Matthew Smillie wrote:

On Jun 20, 2006, at 15:17, James Edward Gray II wrote:

Not comparing on id:

irb(main):006:0> [['a'],['a']].each{|ar| puts ar.id}
99017932
99017908
=> [["a"], ["a"]]
irb(main):007:0> [['a'],['a']].uniq
=> [["a"]]
irb(main):008:0>

···

On 6/20/06, Matthew Smillie <M.B.Smillie@sms.ed.ac.uk> wrote:

On Jun 20, 2006, at 15:17, James Edward Gray II wrote:

> a = [ { :foo => :bar }, { :foo => :bar } ]
>
> p a #=> [{:foo=>:bar}, {:foo=>:bar}]
> p a[0] == a[1] #=> true
> # why does this next call do nothing?
> p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

Seems to compare on object id, rather than with ==. I couldn't
speculate on any more significant answer to 'why?'

a[0].id == a[1].id
=> true

b = [a[0], a[0]]
b.uniq
=> [{:foo=>:bar}]

So which one is uniq() really using? eql?()?

James Edward Gray II

···

On Jun 20, 2006, at 9:26 AM, Kroeger, Simon (ext) wrote:

From: James Edward Gray II [mailto:james@grayproductions.net]
Sent: Tuesday, June 20, 2006 4:17 PM

Would someone please explain this behavior to me?

   a = [ { :foo => :bar }, { :foo => :bar } ]

   p a #=> [{:foo=>:bar}, {:foo=>:bar}]
   p a[0] == a[1] #=> true
   # why does this next call do nothing?
   p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

   # inefficient work-around
   p a.inject() { |cp, e| cp.include?(e) ? cp : cp << e } #=>
[{:foo=>:bar}]

James Edward Gray II

a = [ { :foo => :bar }, { :foo => :bar } ]

class Hash
    def hash
        self.to_a.sort.hash
    end

    def eql? other
        size == other.size && keys.all?{|k| self[k] == other[k]}
    end
end

p a.uniq #=> [{:foo=>:bar}]

Interesting. Thank you for the information.

James Edward Gray II

···

On Jun 20, 2006, at 9:27 AM, ts wrote:

> p a[0] == a[1] #=> true
> # why does this next call do nothing?
> p a.uniq #=> [{:foo=>:bar}, {:foo=>:bar}]

#uniq first create an hash : this mean that it don't use #== for the
comparison.

From: James Edward Gray II [mailto:james@grayproductions.net]
Sent: Tuesday, June 20, 2006 4:32 PM

> p a.uniq #=> [{:foo=>:bar}]

So which one is uniq() really using? eql?()?

James Edward Gray II

both, uniq creates a hash from the array.
Iterating over the array it deletes from the hash and removes
values from the array if there is no such element in the hash
left. To find the element in the hash both methods are necessary.

cheers

Simon

To unsubscribe ML <ruby-talk@ruby-lang.org>, send "unsubscribe" in the mail body
to the address <ruby-talk-ctl@ruby-lang.org>. Also you can send "# unsubscribe".
"#" is prepended in fml documents for some historically reasons. "#"
is NOT NEEDED in almost all cases but fml can accepct commands with or
without '#'. Please ignore this in default configuration.

···

On Jun 20, 2006, at 10:29 AM, Hamid Rasoulian wrote:

Can any body help me with How to "unsubscribe" from the ruby talk
mailing list.

Thanks.

Hamid Rasoulian wrote:

Can any body help me with How to "unsubscribe" from the ruby talk
mailing list.

The mail header of every ruby-talk message includes such instructions.

Look for the List-Unsubscribe header:

<mailto:ruby-talk-ctl@ruby-lang.org?body=unsubscribe>

Thanks.

You're welcome.

···

--
James Britt

"Design depends largely on constraints."
  - Charles Eames

OK, let me expand my question slightly: why are hash() and eql?() not meaningfully defined for Hash?

Doesn't Array.hash just aggregate the hash() of its elements? Why could Hash not do the same?

Thanks all for the information.

James Edward Gray II

···

On Jun 20, 2006, at 9:45 AM, Kroeger, Simon (ext) wrote:

From: James Edward Gray II [mailto:james@grayproductions.net]
Sent: Tuesday, June 20, 2006 4:32 PM

p a.uniq #=> [{:foo=>:bar}]

So which one is uniq() really using? eql?()?

James Edward Gray II

both, uniq creates a hash from the array.

There's also Hash#default and Hash#default_proc to take in mind.
And you can't rely on Proc#hash and friends...
Otherwise, it's trivially implementable.

···

On Tue, Jun 20, 2006 at 11:56:21PM +0900, James Edward Gray II wrote:

>>So which one is uniq() really using? eql?()?
>
>both, uniq creates a hash from the array.

OK, let me expand my question slightly: why are hash() and eql?()
not meaningfully defined for Hash?

Doesn't Array.hash just aggregate the hash() of its elements? Why
could Hash not do the same?

--
Mauricio Fernandez - http://eigenclass.org - singular Ruby