获取数组元素的索引比O(n)更快

时间:2011-06-05 10:22:38

标签: ruby arrays performance indexing

鉴于我有一个巨大的数组,并且有一个值。我想得到数组中的值的索引。还有其他方式,而不是调用Array#index来获取它吗?问题来自于需要保留非常庞大的数组并且需要大量调用Array#index

经过几次尝试后,我发现缓存索引在元素内部通过存储带有(value, index)字段的结构而不是值本身,在性能上提供了巨大的一步(胜利的20倍)。 / p>

我仍然想知道是否有一种更方便的方法来查找en元素的索引而不进行缓存(或者有一种很好的缓存技术可以提高性能)。

8 个答案:

答案 0 :(得分:199)

为什么不使用index或rindex?

array = %w( a b c d e)
# get FIRST index of element searched
puts array.index('a')
# get LAST index of element searched
puts array.rindex('a')
  

索引:http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-index

     

rindex:http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-rindex

答案 1 :(得分:117)

将数组转换为哈希值。然后寻找钥匙。

array = ['a', 'b', 'c']
hash = Hash[array.map.with_index.to_a]    # => {"a"=>0, "b"=>1, "c"=>2}
hash['b'] # => 1

答案 2 :(得分:9)

其他答案没有考虑在数组中多次列出条目的可能性。这将返回一个散列,其中每个键是数组中的唯一对象,每个值都是一个索引数组,对应于对象所在的位置:

a = [1, 2, 3, 1, 2, 3, 4]
=> [1, 2, 3, 1, 2, 3, 4]

indices = a.each_with_index.inject(Hash.new { Array.new }) do |hash, (obj, i)| 
    hash[obj] += [i]
    hash
end
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5], 4 => [6] }

这样可以快速搜索重复的条目:

indices.select { |k, v| v.size > 1 }
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5] }

答案 3 :(得分:6)

有没有充分的理由不使用哈希?数组的查找次数为O(1)O(n)

答案 4 :(得分:2)

如果是排序数组,您可以使用二进制搜索算法(O(log n))。例如,使用此功能扩展Array类:

class Array
  def b_search(e, l = 0, u = length - 1)
    return if lower_index > upper_index

    midpoint_index = (lower_index + upper_index) / 2
    return midpoint_index if self[midpoint_index] == value

    if value < self[midpoint_index]
      b_search(value, lower_index, upper_index - 1)
    else
      b_search(value, lower_index + 1, upper_index)
    end
  end
end

答案 5 :(得分:2)

结合@ sawa的答案和那里列出的评论,你可以在数组类上实现“快速”索引和rindex。

class Array
  def quick_index el
    hash = Hash[self.map.with_index.to_a]
    hash[el]
  end

  def quick_rindex el
    hash = Hash[self.reverse.map.with_index.to_a]
    array.length - 1 - hash[el]
  end
end

答案 6 :(得分:1)

如果您的数组具有自然顺序,请使用二进制搜索。

使用二分搜索。

二进制搜索的访问时间为O(log n)

以下是如何使用二进制搜索的步骤,

  • 你阵列的排序是什么?例如,它是按名称排序的吗?
  • 使用bsearch查找元素或索引

代码示例

# assume array is sorted by name!

array.bsearch { |each| "Jamie" <=> each.name } # returns element
(0..array.size).bsearch { |n| "Jamie" <=> array[n].name } # returns index

答案 7 :(得分:0)

  

我仍然想知道是否有一种更方便的方法来查找en元素的索引而不进行缓存(或者有一种好的缓存技术可以提高性能)。

您可以使用二进制搜索(如果您的数组是有序的 ,并且您存储在数组中的值在某种程度上是可比的)。为此,您需要能够告诉二进制搜索是在当前元素的“左侧”还是“右侧”查找。但是我相信,在插入时存储index并从同一数组获取元素时再使用它并没有错。