Ruby: compare matrices y obtenga un índice según la condición
Tengo dos matrices
array_input = %w[one two three two]
array_compare = %w[one two three four five]
Quiero extraer el índice 'más alto' de la matriz array_compare, si el valor existe en la matriz de entrada. La salida deseada es la 2
que three
existe en la matriz de entrada y la compare
matriz.
He intentado
val = nil
array_compare.reverse_each do |v|
val = v and break if array_input.include? v
end
pero no establece val.
Respuestas
Uno podría escribir
array_compare.rindex { |e| array_input.include?(e) }
#=> 2
pero eso requiere una búsqueda lineal de array_input
para cada elemento de array_compare
(comenzando con el último) hasta que se encuentre una coincidencia. Mejor es lo siguiente.
array_compare.rindex((array_compare & array_input).last)
#=> 2
Los pasos son los siguientes.
a = array_compare & array_input
#=> ["one", "two", "three"]
Consulte Array # & . Tenga en cuenta que "El orden se conserva de la matriz original [ array_compare
].". Esta operación de una sola pasada será muy rápida ya que se implementa en C. Continuando,
e = a.last
#=> "three"
array_compare.rindex(e)
#=> 2
Consulte Array # rindex .
Si entiendo bien
extraer el índice 'más alto' de la matriz array_compare, si el valor existe en la matriz de entrada,
esta podría ser una opción:
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]
, vuelve 5
.
Convierta la matriz utilizada para las búsquedas en un conjunto , para una búsqueda más rápida.
Itere desde el final de la matriz donde está buscando el índice máximo (como lo está haciendo correctamente), también la velocidad. Las soluciones que se repiten desde el principio de la matriz y eligen el índice máximo son generalmente más lentas debido a todas las búsquedas inútiles hasta que se encuentra el último elemento coincidente. El método siguiente se detiene rápidamente, en la primera coincidencia exitosa.
Finalmente, corrija el índice máximo, ya que array_compare.reverse.each_with_index
devuelve índices de la matriz invertida .
El código resultante puede ser más largo que en muchas de las otras respuestas, pero es simple y rápido:
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
VER TAMBIÉN:
Array.include? es relativamente lento. Además, si necesita un hash solo para la búsqueda, considere usar un conjunto:https://stackoverflow.com/a/411164/967621
Más sobre las comparaciones de velocidad para matrices, conjuntos y hashes (con puntos de referencia): Ventajas de Set en ruby
La solución más eficaz que se me ocurrió es:
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
Tenga en cuenta que el argumento set_input
es un Set, no un Array. Convertir una matriz en un conjunto tiene sentido, pero solo si desea llamar find_last_index
muchas veces con el mismo conjunto. De lo contrario, el proceso de convertir una matriz en un conjunto ( to_set
) lleva más tiempo del que puede ganar usando a en Set#include?
lugar de Array#include?
. Entonces, si desea usar find_last_index
solo una vez, no debe llamar find_last_index(array_input.to_set, array_compare)
, sino usar esta versión que no usa conjuntos en absoluto:
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
Es posible que desee ver este punto de referencia de diferentes soluciones a este problema.
Acabo de ejecutar (copiar y pegar) su código en irb , y después val
fui "tres". ¿Realmente inspeccionó val
después, es decir
p val
? Aquí hay una captura de pantalla de mi transcripción .