Ruby - Dizileri karşılaştır ve koşula göre dizini al

Aug 18 2020

İ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ış 2olarak threegiriş dizisi ve var comparedizi.

denedim

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

ama val ayarlamaz.

Yanıtlar

1 CarySwoveland Aug 19 2020 at 02:30

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 .

2 iGian Aug 18 2020 at 22:14

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.

2 TimurShtatland Aug 18 2020 at 23:18

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_indexdizinlerini 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ı

1 TeWu Aug 19 2020 at 18:12

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_inputa 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_indexaynı 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 .

user1934428 Aug 18 2020 at 18:32

Kodunuzu irb'de çalıştırdım (kopyalayıp yapıştırdım) ve valdaha sonra "üç" oldum . valDaha sonra gerçekten incelediniz mi?

p val

? İşte transkriptimin ekran görüntüsü .