Ruby: compare matrices y obtenga un índice según la condición

Aug 18 2020

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 2que threeexiste en la matriz de entrada y la comparematriz.

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

1 CarySwoveland Aug 19 2020 at 02:30

Uno podría escribir

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

pero eso requiere una búsqueda lineal de array_inputpara 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 .

2 iGian Aug 18 2020 at 22:14

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.

2 TimurShtatland Aug 18 2020 at 23:18

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_indexdevuelve í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

1 TeWu Aug 19 2020 at 18:12

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_inputes un Set, no un Array. Convertir una matriz en un conjunto tiene sentido, pero solo si desea llamar find_last_indexmuchas 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_indexsolo 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.

user1934428 Aug 18 2020 at 18:32

Acabo de ejecutar (copiar y pegar) su código en irb , y después valfui "tres". ¿Realmente inspeccionó valdespués, es decir

p val

? Aquí hay una captura de pantalla de mi transcripción .