web-dev-qa-db-fra.com

Récupère l'index de l'élément de tableau plus vite que O(n)

Étant donné que j'ai un tableau énorme, et une valeur de celui-ci. Je veux obtenir l'index de la valeur dans le tableau. Y a-t-il un autre moyen, plutôt que d'appeler Array#index pour l'obtenir? Le problème vient de la nécessité de garder un très grand tableau et d’appeler Array#index énormément de fois.

Après quelques essais, j'ai trouvé que mise en cache indexe à l'intérieur des éléments en stockant les structures avec (value, index) _ champs au lieu de la valeur elle-même représente un énorme progrès en termes de performances (20 fois le gain).

Je me demande tout de même s’il existe un moyen plus pratique de rechercher l’index d’un élément en l’absence de mise en cache (ou qu’il existe une bonne technique de mise en cache qui permettra d’améliorer les performances).

102
gmile

Convertissez le tableau en un hachage. Ensuite, cherchez la clé.

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

Pourquoi ne pas utiliser index ou 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')

index: 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

199
Roger

D'autres réponses ne prennent pas en compte la possibilité d'une entrée répertoriée plusieurs fois dans un tableau. Cela retournera un hachage où chaque clé est un objet unique dans le tableau et chaque valeur est un tableau d'indices qui correspond à l'endroit où l'objet vit:

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] }

Cela permet une recherche rapide des entrées en double:

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

Y a-t-il une bonne raison de ne pas utiliser de hash? Les recherches sont O(1) vs. O(n) pour le tableau.

6
Erik Peterson

Si c'est un tableau trié, vous pouvez utiliser un algorithme de recherche binaire (O(log n)). Par exemple, étendre la classe Array avec cette fonctionnalité:

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
3
isakkarlsson

En combinant la réponse de @ sawa et le commentaire qui y est répertorié, vous pouvez implémenter un index "rapide" et un rindex sur la classe array.

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
2
ianstarz

Si votre tableau a un ordre naturel, utilisez la recherche binaire.

Utilisez la recherche binaire.

La recherche binaire a O(log n) temps d'accès.

Voici les étapes à suivre pour utiliser la recherche binaire,

  • Quelle est la commande de votre tableau? Par exemple, est-il trié par nom?
  • Utilisez bsearch pour trouver des éléments ou des index

Exemple de code

# 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
2
akuhn

Je me demande tout de même s’il existe un moyen plus pratique de rechercher l’index d’un élément en l’absence de mise en cache (ou qu’il existe une bonne technique de mise en cache qui permettra d’améliorer les performances).

Vous pouvez utiliser la recherche binaire (si votre tableau est ordonné et les valeurs que vous stockez dans le tableau sont comparables d'une manière ou d'une autre). Pour que cela fonctionne, vous devez être capable de dire à la recherche binaire si elle doit regarder "à gauche" ou "à droite" de l'élément en cours. Mais je pense qu’il n’ya rien de mal à stocker le index au moment de l’insertion et à l’utiliser ensuite si vous obtenez l’élément du même tableau.

0
Julik