我正在尝试比较外部定义的对象的数组。我希望我能够做一个简单的.difference
,这是在Ruby 2.6.0中引入的功能,但在查看之后:https://ruby-doc.org/core-core-core-2.6/array.html#method-i-i - 差异我不确定我是否可以指定自定义比较。
好的,假设我们有一个简单的对象num
# Pretend we don't have access to this, just for reference
class Num
def initialize(val)
@val = val
end
def val
@val
end
end
我有两个数组,一个是另一个子集。我想找到子集缺失的内容。在以下示例中,我希望区别是具有值3的对象,因为它在子集中不存在。
all = [Num.new(1), Num.new(2), Num.new(3)]
subset = [Num.new(1), Num.new(2)]
默认的.difference
函数在两个对象之间使用.eql?
进行比较,因此差异不会给出预期的结果:
all.difference(subset)
=> [#<Num:0x00007fcae19e9540 @val=1>, #<Num:0x00007fcae19e9518 @val=2>, #<Num:0x00007fcae19e94f0 @val=3>]
我能够创建自己的自定义骇客解决方案,以正确地给我想要的值:
def custom_difference(all, subset)
diff = all.reject { |all_curr|
subset.find{ |subset_curr|
subset_curr.val == all_curr.val
} != nil
}
end
custom_difference(all, subset)
=> [#<Num:0x00007fcae19e94f0 @val=3>]
,但我想知道是否有使用现有的.difference
函数,我也尝试使用这样的使用,以覆盖比较两个对象的方式:
all.difference(subset) { |a, b|
a.val <=> b.val
}
=> [#<Num:0x00007fcae19e9540 @val=1>, #<Num:0x00007fcae19e9518 @val=2>, #<Num:0x00007fcae19e94f0 @val=3>]
但这并没有任何事情来调整比较发生的方式(AFAIK(我做错了什么吗?这是不可能的吗?:'(
如果您不想将eql?
添加到Aleksei Matiushkin所述(例如,如果您想对不同的事情使用多个标准(,则无法重用#difference
。做您在做的事情几乎是您需要做的事情,尽管使用Array#include?
是O(n^2(,所以我喜欢在其中粘贴Set
:
Set.new(subset.map(&:val)).then { |s| all.reject { |x| s === x.val } }
# => [#<Num:0x00007febd32330e0 @val=3>]
或作为一种新方法:
module ArrayWithDifferenceBy
refine Array do
def difference_by(other)
other_set = Set.new(other.map { |x| yield x })
self.reject { |x| other_set.include?(yield x) }
end
end
end
module TestThis
using ArrayWithDifferenceBy
all = [Num.new(1), Num.new(2), Num.new(3)]
subset = [Num.new(1), Num.new(2)]
all.difference_by(subset, &:val)
end
# => [#<Num:0x00007febd32330e0 @val=3>]
您只想在对象上覆盖#eql?
。
class Num
def initialize(val)
@val = val
end
def val
@val
end
def eql?(comp)
@val == comp.val
end
end
现在尝试:
all = [Num.new(1), Num.new(2), Num.new(3)]
subset = [Num.new(1), Num.new(2)]
all.difference(subset) => [#<Num:0x00007fa7f7171e60 @val=3>]