Ruby - compare matrizes e obtenha índice com base na condição

Aug 18 2020

Eu tenho duas matrizes

array_input = %w[one two three two]
array_compare = %w[one two three four five]

Quero extrair o índice 'mais alto' da matriz array_compare, se o valor existir na matriz de entrada. O resultado desejado é 2que threeexiste na matriz de entrada e a comparematriz.

eu tentei

val = nil
array_compare.reverse_each do |v|
  val = v and break if array_input.include? v
end

mas não define val.

Respostas

1 CarySwoveland Aug 19 2020 at 02:30

Alguém poderia escrever

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

mas isso requer uma pesquisa linear de array_inputpara cada elemento de array_compare(começando com o último) até que uma correspondência seja encontrada. Melhor é o seguinte.

array_compare.rindex((array_compare & array_input).last)
  #=> 2

As etapas são as seguintes.

a = array_compare & array_input
  #=> ["one", "two", "three"]

Consulte Array # & . Observe que "A ordem é preservada do array original [ array_compare].". Esta operação de uma passagem será muito rápida, pois é implementada em C. Continuando,

e = a.last
  #=> "three" 
array_compare.rindex(e)
  #=> 2

Consulte Array # rindex .

2 iGian Aug 18 2020 at 22:14

Se bem entendi,

extraia o índice 'mais alto' da matriz array_compare, se o valor existir na matriz de entrada,

isso pode ser uma opção:

array_compare.map.with_index { |e, id| id if array_input.include? e }.compact.max #=> 2

Se array_compare = %w[one two three four five three], ele retorna 5.

2 TimurShtatland Aug 18 2020 at 23:18

Converta a matriz usada para pesquisas em um conjunto , para uma pesquisa mais rápida.
Itere a partir do final do array onde você está procurando o índice máximo (como você está fazendo corretamente), também para velocidade. Soluções que iteram desde o início da matriz e escolhem o índice máximo são geralmente mais lentas devido a todas as pesquisas inúteis até que o último elemento correspondente seja encontrado. O método abaixo para rapidamente - na primeira partida bem-sucedida.
Finalmente, corrija o índice máximo, pois array_compare.reverse.each_with_indexretorna os índices da matriz invertida .
O código resultante pode ser mais longo do que em muitas das outras respostas, mas é simples e 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

VEJA TAMBÉM:

Array.include? é relativamente lento. Além disso, se você precisar de um hash apenas para pesquisa, considere usar um conjunto:https://stackoverflow.com/a/411164/967621

Mais sobre comparações de velocidade para arrays, sets e hashes (com benchmarks): Vantagens de Set em ruby

1 TeWu Aug 19 2020 at 18:12

A solução de melhor desempenho que eu poderia propor é:

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

Observe que o argumento set_inputé a Set, não um Array. Converter um array em um conjunto faz sentido, mas apenas se você quiser chamar find_last_indexmuitas vezes com o mesmo conjunto. Caso contrário, o processo de conversão de um array em set ( to_set) leva mais tempo do que você pode ganhar usando um em Set#include?vez de um Array#include?. Então, se você quiser usar find_last_indexapenas uma vez, você não deve chamar find_last_index(array_input.to_set, array_compare), mas sim esta versão que não usa conjuntos:

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

Você pode querer ver este benchmark de diferentes soluções para este problema.

user1934428 Aug 18 2020 at 18:32

Acabei de executar (copiar e colar) seu código no irb , e fiquei val"três" depois. Você realmente inspecionou valdepois, ou seja,

p val

? Aqui está uma captura de tela da minha transcrição .