Ruby - Comparez les tableaux et obtenez l'index en fonction de la condition

Aug 18 2020

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 2telle qu'elle threeexiste dans le tableau d'entrée et le comparetableau.

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

1 CarySwoveland Aug 19 2020 at 02:30

On pourrait écrire

array_compare.rindex { |e| array_input.include?(e) }
  #=> 2

mais cela nécessite une recherche linéaire de array_inputpour 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 .

2 iGian Aug 18 2020 at 22:14

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.

2 TimurShtatland Aug 18 2020 at 23:18

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_indexrenvoie 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

1 TeWu Aug 19 2020 at 18:12

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_inputest a Set, pas un Array. La conversion d'un tableau en un ensemble a du sens, mais uniquement si vous souhaitez appeler find_last_indexplusieurs 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_indexqu'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.

user1934428 Aug 18 2020 at 18:32

Je viens d'exécuter (copier et coller) votre code dans irb , et j'ai valété "trois" après. Avez-vous effectivement inspecté valaprès, c.-à-d.

p val

? Voici une capture d'écran de ma transcription .