Ruby - Dizileri karşılaştır ve koşula göre dizini al
İki dizim var
array_input = %w[one two three two]
array_compare = %w[one two three four five]
Değer girdi dizisinde mevcutsa, array_compare dizisinden 'en yüksek' dizini çıkarmak istiyorum. İstenen çıkış 2
olarak three
giriş dizisi ve var compare
dizi.
denedim
val = nil
array_compare.reverse_each do |v|
val = v and break if array_input.include? v
end
ama val ayarlamaz.
Yanıtlar
Biri yazabilir
array_compare.rindex { |e| array_input.include?(e) }
#=> 2
ancak bu, bir eşleşme bulunana kadar (sondan başlayarak) array_input
öğesinin her bir öğesi için doğrusal bir arama gerektirir array_compare
. Aşağıdaki daha iyi.
array_compare.rindex((array_compare & array_input).last)
#=> 2
Adımlar aşağıdaki gibidir.
a = array_compare & array_input
#=> ["one", "two", "three"]
Bkz. Dizi # & . "Sıranın orijinal [ array_compare
] dizisinden korunduğuna " dikkat edin. Bu tek geçişli işlem C de uygulandığı için çok hızlı olacak.
e = a.last
#=> "three"
array_compare.rindex(e)
#=> 2
Bkz. Dizi # rindex .
Doğru anlarsam
Değer girdi dizisinde mevcutsa array_compare dizisinden 'en yüksek' dizini çıkarın,
bu bir seçenek olabilir:
array_compare.map.with_index { |e, id| id if array_input.include? e }.compact.max #=> 2
Eğer array_compare = %w[one two three four five three]
dönerse 5
.
Daha hızlı arama için aramalarda kullanılan diziyi bir kümeye dönüştürün .
Maksimum indeksi (doğru yaptığınız gibi) aradığınız dizinin sonundan itibaren hız için yineleyin. Dizinin başından itibaren yinelenen ve maksimum dizini seçen çözümler, en son eşleşen öğe bulunana kadar tüm gereksiz aramalar nedeniyle genellikle daha yavaştır. Aşağıdaki yöntem hızlı bir şekilde durur - ilk başarılı maçta.
Son olarak, tersine çevrilmiş dizinin array_compare.reverse.each_with_index
dizinlerini döndürdüğü için maksimum dizini düzeltin . Ortaya çıkan kod, diğer cevapların çoğundan daha uzun olabilir, ancak hem basit hem de hızlıdır:
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
AYRICA BAKINIZ:
Array.include? nispeten yavaştır. Ayrıca, yalnızca arama için bir karmaya ihtiyacınız varsa, bir küme kullanmayı düşünün:https://stackoverflow.com/a/411164/967621
Diziler, kümeler ve karmalar için hız karşılaştırmaları hakkında daha fazla bilgi (kıyaslamalarla): Ruby'de Ayarlamanın Avantajları
Bulabildiğim en performanslı çözüm şudur:
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
Argümanın set_input
a olduğunu Set, bir olmadığını unutmayın Array. Bir diziyi bir kümeye dönüştürmek mantıklıdır, ancak yalnızca find_last_index
aynı küme ile birçok kez çağrı yapmak istiyorsanız . Aksi takdirde, bir diziyi bir sete ( to_set
) dönüştürme işlemi, bir Set#include?
yerine a kullanarak kazanabileceğinizden daha fazla zaman alır Array#include?
. Bu nedenle find_last_index
, yalnızca bir kez kullanmak istiyorsanız , aramamalısınız find_last_index(array_input.to_set, array_compare)
, bunun yerine setleri kullanmayan bu sürümü kullanmalısınız:
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
Bu soruna farklı çözümlerin bu karşılaştırmasını görmek isteyebilirsiniz .
Kodunuzu irb'de çalıştırdım (kopyalayıp yapıştırdım) ve val
daha sonra "üç" oldum . val
Daha sonra gerçekten incelediniz mi?
p val
? İşte transkriptimin ekran görüntüsü .