有什么方法可以指定如何比较 Ruby 2.6.0 中的 .difference 函数的对象数组?
Is there any way to specify how to compare of array of objects for .difference function in Ruby 2.6.0?
我正在尝试比较一组外部定义的对象。我希望我能够做一个简单的 .difference
,一个在 Ruby 2.6.0 中引入的函数,但在查看它之后:https://ruby-doc.org/core-2.6/Array.html#method-i-difference 我不确定我可以指定自定义比较。
好的,假设我们有一个简单的 Object 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>]
我能够创建自己的自定义 hacky 解决方案来正确地给我想要的值:
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?
。
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>]
如果您不想按照 Aleksei Matiushkin 的描述将 eql?
添加到 class(例如,如果您想对不同的事物使用多个标准),则无法重用 #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>]
我正在尝试比较一组外部定义的对象。我希望我能够做一个简单的 .difference
,一个在 Ruby 2.6.0 中引入的函数,但在查看它之后:https://ruby-doc.org/core-2.6/Array.html#method-i-difference 我不确定我可以指定自定义比较。
好的,假设我们有一个简单的 Object 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>]
我能够创建自己的自定义 hacky 解决方案来正确地给我想要的值:
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?
。
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>]
如果您不想按照 Aleksei Matiushkin 的描述将 eql?
添加到 class(例如,如果您想对不同的事物使用多个标准),则无法重用 #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>]