当我在包含自定义对象的两个数组上调用first_array | second_array
时:
first_array = [co1, co2, co3]
second_array =[co2, co3, co4]
它返回[co1, co2, co3, co2, co3, co4]
。它不会删除重复项。我试图在结果上调用uniq
,但它也没有用。我该怎么办?
更新
这是自定义对象:
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
当我创建几个Task类型的实例并将它们放入两个不同的数组时,当我尝试调用'|'时对它们没有任何反应只会返回包含第一个和第二个数组元素的数组,而不会删除重复项。
答案 0 :(得分:3)
如果您没有实现正确的相等方法,那么如果两个对象不同,那么自身的编程语言就无法识别。 在ruby的情况下你需要实现eql?并在您的类定义中使用哈希,因为这些是Array类用于检查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
例如:
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
从Array中删除b只留下一个对象
希望这有帮助!
答案 1 :(得分:2)
uniq
方法可以采用一个块来定义比较对象的内容。例如:
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
答案 2 :(得分:0)
如果您查看Array#|运算符,则表示它使用eql?
- 方法,Object上的方法与==
方法相同。您可以通过mixin在Comparable - 模块中定义,然后实现<=>
- 方法,然后您将免费获得许多比较方法。
<=>
运算符非常易于实现:
def <=>(obj)
return -1 if this < obj
return 0 if this == obj
return 1 if this > obj
end
答案 3 :(得分:0)
关于你的'更新',这就是你正在做的事情:
a = Task.new # => #<Task:0x007f8d988f1b78>
b = Task.new # => #<Task:0x007f8d992ea300>
c = [a,b] # => [#<Task:0x007f8d988f1b78>, #<Task:0x007f8d992ea300>]
a = Task.new # => #<Task:0x007f8d992d3e48>
d = [a] # => [#<Task:0x007f8d992d3e48>]
e = c|d # => [#<Task:0x007f8d988f1b78>, #<Task:0x007f8d992ea300>, \
#<Task:0x007f8d992d3e48>]
然后建议e = [a, b, a]
?如果是这样,那就是问题,因为a
不再指向#<Task:0x007f8d988f1b78>
。你只能说e => [#<Task:0x007f8d988f1b78>, b, a]
答案 4 :(得分:0)
我冒昧地重写你的类并添加需要覆盖的方法以便使用uniq(hash和eql?)。
class Task
METHODS = [:status, :description, :priority, :tags]
attr_accessor *METHODS
def initialize task_line
@status, @description, @priority, @tags = *task_line.split("|")
@tags = @tags.split(",")
end
def eql? another_task
METHODS.all?{|m| self.send(m)==another_task.send(m)}
end
alias_method :==, :eql? #Strictly not needed for array.uniq
def hash
[@status, @description, @priority, @tags].hash
end
end
x = [Task.new('1|2|3|4'), Task.new('1|2|3|4')]
p x.size #=> 2
p x.uniq.size #=> 1
答案 5 :(得分:0)
我尝试了上面fsaravia
的解决方案,但对我来说并没有用。我尝试过Ruby 2.3.1和Ruby 2.4.0。
我发现的解决方案与fsaravia
发布的解决方案非常相似,只需稍加调整即可。所以这就是:
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
请注意,我已经删除了我的示例中的@
。它不会影响解决方案本身。只是,IMO,没有任何理由直接访问实例变量,因为设置了一个读取器方法。
所以...我真正改变的是在eql?
方法中找到的,我用hash
代替name
。就是这样!