Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing objects in ruby

Consider this:

class Aaa
  attr_accessor :a, :b
end

x = Aaa.new
x.a, x.b = 1,2
y = Aaa.new
y.a, y.b = 1,2

puts x == y #=>false

Is there some way to check if all public attributes are equal in classes of same type?

like image 484
dfens Avatar asked Oct 15 '10 09:10

dfens


People also ask

How do you check if two objects are the same in Ruby?

method. This method tests object equality by checking if the 2 objects refer to the same hash key. Here, the instances assigned to the key and other_key variables are 2 distinct instances. Now, if the Hash#[]= method made the comparison at an object-level then it'd rather create an entry for each string.

Can you use == to compare objects?

The == operator compares whether two object references point to the same object.

How do you compare two objects?

The equals() method of the Object class compare the equality of two objects. The two objects will be equal if they share the same memory address. Syntax: public boolean equals(Object obj)


3 Answers

class Aaa
  attr_accessor :a, :b

  def ==(other)
    return self.a == other.a && self.b == other.b
  end
end

x = Aaa.new
x.a,x.b = 1,2
y = Aaa.new
y.a,y.b = 1,2
y = Aaa.new
y.a,y.b = 1,2
z = Aaa.new
z.a,z.b = 1,3

x == y # => true
x == z # => false
like image 164
Jason Noble Avatar answered Oct 21 '22 04:10

Jason Noble


Aaa = Struct.new(:a, :b)

x = Aaa.new
x.a, x.b = 1,2
y = Aaa.new
y.a, y.b = 1,2

x == y #=> true

Struct defines ==, eql?, and hash for you, so that two Aaas are equal, if their values for a and b are equal. It also defines initialize so that you can optionally pass in the values for a and b when creating the object (Aaa.new(value_for_a, value_for_b)). And it defines to_a to return [a,b].

You can also use Struct.new with a block to define additional methods, so you have the full power of a "normal" class:

Aaa = Struct.new(:a, :b) do
  def c
    a+b
  end
end
Aaa.new(23,42).c #=> 65
like image 43
sepp2k Avatar answered Oct 21 '22 05:10

sepp2k


We can easily generalize to any number of instances and drop the requirement for getters for the instance variables:

class Aaa
  def initialize(a,b,c)
    @a, @b, @c = a, b, c
  end
end

x = Aaa.new(1,2,3)
y = Aaa.new(1,2,3)
z = Aaa.new(1,2,3)
arr = [x,y,z]

x.instance_variables.map do |v|
  arr.map { |i| i.send(:instance_variable_get,v) }.uniq.size == 1
end.all?
  #=>true

Change z to:

z = Aaa.new(1,2,4)

then:

x.instance_variables.map do |v|
  arr.map { |i| i.send(:instance_variable_get,v) }.uniq.size == 1
end.all?
  #=> false
like image 28
Cary Swoveland Avatar answered Oct 21 '22 04:10

Cary Swoveland