Ruby - Comparez les tableaux et obtenez l'index en fonction de la condition
J'ai deux tableaux
array_input = %w[one two three two]
array_compare = %w[one two three four five]
Je veux extraire l'index «le plus élevé» du tableau array_compare, si la valeur existe dans le tableau d'entrée. La sortie souhaitée est 2
telle qu'elle three
existe dans le tableau d'entrée et le compare
tableau.
J'ai essayé
val = nil
array_compare.reverse_each do |v|
val = v and break if array_input.include? v
end
mais il ne définit pas val.
Réponses
On pourrait écrire
array_compare.rindex { |e| array_input.include?(e) }
#=> 2
mais cela nécessite une recherche linéaire de array_input
pour chaque élément de array_compare
(en commençant par le dernier) jusqu'à ce qu'une correspondance soit trouvée. Mieux vaut le suivant.
array_compare.rindex((array_compare & array_input).last)
#=> 2
Les étapes sont les suivantes.
a = array_compare & array_input
#=> ["one", "two", "three"]
Voir Array # & . Notez que "L'ordre est conservé à partir du tableau d'origine [ array_compare
].". Cette opération en un seul passage sera très rapide car elle est mise en œuvre en C.
e = a.last
#=> "three"
array_compare.rindex(e)
#=> 2
Voir Array # rindex .
Si je comprends bien,
extraire l'index 'le plus élevé' du tableau array_compare, si la valeur existe dans le tableau d'entrée,
cela pourrait être une option:
array_compare.map.with_index { |e, id| id if array_input.include? e }.compact.max #=> 2
Si array_compare = %w[one two three four five three]
, il revient 5
.
Convertissez le tableau utilisé pour les recherches en un ensemble , pour une recherche plus rapide.
Itérez à partir de la fin du tableau où vous recherchez l'index max (comme vous le faites correctement), également pour la vitesse. Les solutions qui itèrent depuis le début du tableau et choisissent l'index max sont généralement plus lentes en raison de toutes les recherches inutiles jusqu'à ce que le dernier élément correspondant soit trouvé. La méthode ci-dessous s'arrête rapidement - au premier match réussi.
Enfin, corrigez l'index max, car array_compare.reverse.each_with_index
renvoie les index du tableau inversé .
Le code résultant peut être plus long que dans la plupart des autres réponses, mais il est à la fois simple et rapide:
require 'set'
array_input = %w[one two three two]
array_compare = %w[one two three four five]
set_input = array_input.to_set
i_max = nil
array_compare.reverse.each_with_index { |x, i| i_max = i and break if set_input.include? x }
# correct the index to count from the beginning of
# array_compare, not from the end:
i_max = array_compare.length - i_max - 1;
puts i_max; # prints: 2
VOIR ÉGALEMENT:
Array.include? est relativement lent. De plus, si vous avez besoin d'un hachage pour la recherche uniquement, envisagez d'utiliser un ensemble:https://stackoverflow.com/a/411164/967621
En savoir plus sur les comparaisons de vitesse pour les tableaux, les ensembles et les hachages (avec des repères): avantages de Set in ruby
La solution la plus performante que je pourrais proposer est:
def find_last_index(set_input, array_compare)
(array_compare.length - 1).downto(0) do |i|
return i if set_input.include?(array_compare[i])
end
end
Notez que l'argument set_input
est a Set, pas un Array. La conversion d'un tableau en un ensemble a du sens, mais uniquement si vous souhaitez appeler find_last_index
plusieurs fois avec le même ensemble. Sinon, le processus de conversion d'un tableau en set ( to_set
) prend plus de temps que ce que vous pouvez gagner en utilisant a Set#include?
au lieu d'un Array#include?
. Donc, si vous ne voulez utiliser find_last_index
qu'une seule fois, vous ne devriez pas appeler find_last_index(array_input.to_set, array_compare)
, mais plutôt utiliser cette version qui n'utilise pas du tout de sets:
def find_last_index(array_input, array_compare)
(array_compare.length - 1).downto(0) do |i|
return i if array_input.include?(array_compare[i])
end
end
Vous voudrez peut-être voir cette référence des différentes solutions à ce problème.
Je viens d'exécuter (copier et coller) votre code dans irb , et j'ai val
été "trois" après. Avez-vous effectivement inspecté val
après, c.-à-d.
p val
? Voici une capture d'écran de ma transcription .