When I call first_array | second_array
on two arrays that contain custom objects:
first_array = [co1, co2, co3]
second_array =[co2, co3, co4]
it returns [co1, co2, co3, co2, co3, co4]
. It doesn't remove the duplicates. I tried to call uniq
on the result, but it didn't work either. What should I do?
Update:
This is the custom object:
class Task
attr_accessor :status, :description, :priority, :tags
def initiate_task task_line
@status = task_line.split("|")[0]
@description = task_line.split("|")[1]
@priority = task_line.split("|")[2]
@tags = task_line.split("|")[3].split(",")
return self
end
def <=>(another_task)
stat_comp = (@status == another_task.status)
desc_comp = (@description == another_task.description)
prio_comp = (@priority == another_task.priority)
tags_comp = (@tags == another_task.tags)
if(stat_comp&desc_comp&prio_comp&tags_comp) then return 0 end
end
end
and when I create few instances of Task type and drop them into two different arrays and when I try to call '|' on them nothing happens it just returns array including both first and second array's elements without the duplicates removed.
No programming language for itself can be aware if two objects are different if you don't implement the correct equality methods. In the case of ruby you need to implement eql? and hash in your class definition, as these are the methods that the Array class uses to check for equality as stated on Ruby's Array docs:
def eql?(other_obj)
# Your comparing code goes here
end
def hash
#Generates an unique integer based on instance variables
end
For example:
class A
attr_accessor :name
def initialize(name)
@name = name
end
def eql?(other)
@name.eql?(other.name)
end
def hash
@name.hash
end
end
a = A.new('Peter')
b = A.new('Peter')
arr = [a,b]
puts arr.uniq
Removes b from Array leaving only one object
Hope this helps!
The uniq
method can take a block that defines what to compare the objects on. For example:
class Task
attr_accessor :n
def initialize(n)
@n = n
end
end
t1 = Task.new(1)
t2 = Task.new(2)
t3 = Task.new(2)
a = [t1, t2, t3]
a.uniq
#=> [t1, t2, t3] # because all 3 objects are unique
a.uniq { |t| t.n }
#=> [t1, t2] # as it's comparing on the value of n in the object
I tried the solution from fsaravia
above and it didn't work out for me. I tried in both Ruby 2.3.1 and Ruby 2.4.0.
The solution I've found is very similar to what fsaravia
posted though, with a small tweak. So here it is:
class A
attr_accessor :name
def initialize(name)
@name = name
end
def eql?(other)
hash.eql?(other.hash)
end
def hash
name.hash
end
end
a = A.new('Peter')
b = A.new('Peter')
arr = [a,b]
puts arr.uniq
Please, don't mind that I've removed the @
in my example. It won't affect the solution per se. It's just that, IMO, there wasn't any reason to access the instance variable directly, given a reader method was set for that reason.
So...what I really changed is found inside the eql?
method, where I used hash
instead name
. That's it!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With