在ruby中哪个更好,检测或索引,在数组中找到一个对象?

时间:2013-12-14 18:01:15

标签: ruby-on-rails ruby

我有一个对象数组。 我想根据对象的某些属性在数组中找到一个对象。

我能做到

array.detect {|x| x.name=="some name"}

或者我可以做

ind=array.index {|x| x.name=="some name"}
array[ind] unless ind.nil?

有没有理由选择其中一个?

3 个答案:

答案 0 :(得分:1)

如果您不想找到您要搜索的对象的索引值,我建议detect。它将使您无需在访问阵列之前进行nil检查。

从性能的角度来看,我认为它具有相对可比性,但这也可以帮助您做出决定。这将需要Niels B.在评论中提到的基准测试。

答案 1 :(得分:0)

如果要在集合中查找元素,请务必使用为快速检索而创建的集合。数组不是为此而制作的,除非您正在制作堆栈或队列,否则它们也不是特别方便。

以下是一些代码,用于展示使用finddetect或其他常规基于数组的方法提高存储/检索速度的方法:

require 'fruity'
require 'digest'

class Foo

  attr_reader :var1, :var2

  def initialize(var1, var2)
    @var1, @var2 = var1, var2
  end

end

START_INT  = 1
START_CHAR = 'a'
END_INT    = 10
END_CHAR   = 'z'

START_MD5 = Digest::MD5.hexdigest(START_INT.to_s + START_CHAR)
END_MD5   = Digest::MD5.hexdigest(END_INT.to_s   + END_CHAR)

ary = []
hsh = {}
hsh2 = {}

START_INT.upto(END_INT) do |i|
  (START_CHAR .. END_CHAR).each do |j|
    foo = Foo.new(i, j)

    ary << foo
    hsh[[i, j]] = foo
    hsh2[Digest::MD5.hexdigest(i.to_s + j)] = foo
  end
end

compare do

  array_find {
    ary.find { |a| (a.var1 == START_INT) && (a.var2 == START_CHAR) }
    ary.find { |a| (a.var1 == END_INT)   && (a.var2 == END_CHAR)   }
  }

  hash_access_with_array {
    hsh[[START_INT, START_CHAR]]
    hsh[[END_INT, END_CHAR]]
  }

  hash_access_with_digest {
    hsh2[START_MD5]
    hsh2[END_MD5]
  }

end

结果是:

Running each test 16384 times. Test will take about 17 seconds.
hash_access_with_digest is faster than hash_access_with_array by 10x ± 1.0
hash_access_with_array is faster than array_find by 16x ± 1.0

有三种不同的测试,我正在寻找数组ary中的第一个和最后一个元素,以及哈希中的相应对象。查找数组中第一个和最后一个元素的结果将是该搜索的平均时间。为了比较,我在哈希中搜索相同的对象。

如果我们对该对象所在的数组索引有一些预先了解,那么从数组中检索对象会更快,但这就是问题,并且使另一个容器跟踪该信息会比使用哈希更慢

答案 2 :(得分:0)

亲自看看!

require 'benchmark'

array = (1..1000000).to_a

Benchmark.bmbm do |x|
  x.report("#index for 1") {
    array.index(1)
  }

  x.report("#detect 1") {
    array.detect { |i| i == 1 }
  }

  x.report("#index for 500k") {
    array.index(500000)
  }

  x.report("#detect 500k") {
    array.detect { |i| i == 500000 }
  }

  x.report("#index for 1m") {
    array.index(1000000)
  }

  x.report("#detect 1m") {
    array.detect { |i| i == 1000000 }
  }
end

将上面的代码放在一个文件中,然后使用ruby <file>

从控制台执行

忽略顶部块,即排练,底部块看起来应该是这样的:

                      user     system      total        real
#index for 1      0.000005   0.000002   0.000007 (  0.000004)
#detect 1         0.000007   0.000002   0.000009 (  0.000006)
#index for 500k   0.003274   0.000049   0.003323 (  0.003388)
#detect 500k      0.029870   0.000200   0.030070 (  0.030872)
#index for 1m     0.005866   0.000009   0.005875 (  0.005880)
#detect 1m        0.059819   0.000520   0.060339 (  0.061340)

在我的Mac和Ruby 2.5.0上运行时,数字似乎表明#detect#index慢了一个数量级。