gpt4 book ai didi

ruby - 明确指定的方法或 block 的数组差异

转载 作者:行者123 更新时间:2023-12-04 15:24:12 24 4
gpt4 key购买 nike

如果我有数组 ab,表达式 a-b 返回一个包含 a 中所有元素的数组> 不在 b 中。 “不在”在这里表示不等式 (!=)。

在我的例子中,两个数组只包含相同类型的元素(或者,从 ducktyping 的角度来看,只包含理解“相等”方法 f 的元素)。有没有一种简单的方法可以将此 f 指定为相等的标准,以类似的方式我可以在执行 sort 时提供我自己的比较器?目前,我明确地实现了这一点:

# Get the difference a-b, based on 'f':
a.select { |ael| b.all? {|bel| ael.f != bel.f} }

这行得通,但我想知道是否有更简单的方法。

更新:从对这个问题的评论中,我得到的印象是,一个具体的例子将不胜感激。那么,我们开始吧:

class Dummy; end

# Create an Array of Dummy objects.
a = Array.new(99) { Dummy.new }

# Pick some of them at random
b = Array.new(10) { a.sample }

# Now I want to get those elements from a, which are not in b.
diff = a.select { |ael| b.all? {|bel| ael.object_id != bel.object_id} }

当然在这种情况下,我也可以说 ! ael eql? bel,但在我的一般解决方案中,情况并非如此。

最佳答案

例如,“正常”对象相等性数组的哈希和集合操作(​​例如 - 操作)使用 Object#hash 的输出包含对象的方法以及 a.eql?(b) 比较的语义。

这可用于提高性能。 Ruby 在这里假设两个对象是 eql? 如果它们各自的 hash 方法的返回值相同(因此,假设两个对象返回不同的 hash 值不是 eql?)。

对于正常的 a - b 操作,这可以用于首先计算每个对象的 hash 值一次,然后只比较这些值。这相当快。

现在,如果您有自定义相等性,最好的办法是覆盖对象的 hash 方法,以便它们返回适合这些语义的值。

一种常见的方法是构建一个包含所有数据的数组,其中包含对象标识的一部分并获取其哈希值,例如

class MyObject
#...
attr_accessor :foo, :bar

def hash
[self.class, foo, bar].hash
end
end

在您的对象的hash 方法中,您将包括您的f 比较方法当前考虑的所有数据。不是实际使用 f,而是使用所有 Ruby 对象的默认语义,并且可以再次实现对对象的快速设置操作。

但是,如果这不可行(例如,因为您需要基于用例的不同等式语义),您可以自己模拟 ruby​​ 的功能。

使用 f 方法,您可以按如下方式执行设置操作:

def f_difference(a, b)
a_map = a.each_with_object({}) do |a_el, hash|
hash[a_el.f] = a_el
end

b.each do |b_el|
a_map.delete b_el.f
end

a_map.values
end

使用这种方法,您只需计算每个对象的 f 值一次。我们首先用 a 中的所有 f 值和元素构建一个 HashMap ,并根据它们的 f< 从 b 中删除匹配元素 值。其余值是结果。

这种方法使您不必为 a 中的每个对象遍历 b,如果对象很多,这可能会很慢。但是,如果您的每个数组上只有几个对象,那么您原来的方法应该已经没问题了。

让我们看一下基准测试,我使用标准 hash 方法代替您的自定义 f 以获得可比较的结果。

require 'benchmark/ips'

def question_diff(a, b)
a.select { |ael| b.all? {|bel| ael.hash != bel.hash} }
end

def answer_diff(a, b)
a_map = a.each_with_object({}) do |a_el, hash|
hash[a_el.hash] = a_el
end

b.each do |b_el|
a_map.delete b_el.hash
end

a_map.values
end

A = Array.new(100) { rand(10_000) }
B = Array.new(10) { A.sample }

Benchmark.ips do |x|
x.report("question") { question_diff(A, B) }
x.report("answer") { answer_diff(A, B) }

x.compare!
end

使用 Ruby 2.7.1,我在我的机器上得到以下结果,显示问题的原始方法比我的答案的优化版本慢 5.9 倍:

Warming up --------------------------------------
question 1.304k i/100ms
answer 7.504k i/100ms
Calculating -------------------------------------
question 12.779k (± 2.0%) i/s - 63.896k in 5.002006s
answer 74.898k (± 3.3%) i/s - 375.200k in 5.015239s

Comparison:
answer: 74898.0 i/s
question: 12779.3 i/s - 5.86x (± 0.00) slower

关于ruby - 明确指定的方法或 block 的数组差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62656327/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com