Ruby - Bandingkan array dan dapatkan indeks berdasarkan kondisi

Aug 18 2020

Saya memiliki dua array

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

Saya ingin mengekstrak indeks 'tertinggi' dari array_compare array, jika nilainya ada dalam array input. Keluaran yang diinginkan adalah 2seperti yang threeada dalam larik masukan dan comparelarik.

Saya sudah mencoba

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

tetapi tidak mengatur val.

Jawaban

1 CarySwoveland Aug 19 2020 at 02:30

Seseorang bisa menulis

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

tetapi itu membutuhkan pencarian linier array_inputuntuk setiap elemen array_compare(dimulai dengan yang terakhir) hingga ditemukan kecocokan. Yang lebih baik adalah yang berikut ini.

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

Langkah-langkahnya adalah sebagai berikut.

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

Lihat Array # & . Perhatikan bahwa "Urutan dipertahankan dari larik asli [ array_compare].". Operasi sekali jalan ini akan sangat cepat karena diimplementasikan di C. Melanjutkan,

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

Lihat Array # rindex .

2 iGian Aug 18 2020 at 22:14

Jika saya mengerti dengan benar,

ekstrak indeks 'tertinggi' dari array_compare array, jika nilainya ada di array input,

ini bisa menjadi pilihan:

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

Jika array_compare = %w[one two three four five three], itu kembali 5.

2 TimurShtatland Aug 18 2020 at 23:18

Ubah larik yang digunakan untuk pencarian menjadi satu set , untuk pencarian lebih cepat.
Iterasi dari akhir larik tempat Anda mencari indeks maks (seperti yang Anda lakukan dengan benar), juga untuk kecepatan. Solusi yang mengulang dari awal larik dan memilih indeks maks biasanya lebih lambat karena semua pencarian yang tidak berguna hingga elemen terakhir yang cocok ditemukan. Metode di bawah berhenti dengan cepat - pada pertandingan pertama yang berhasil.
Terakhir, perbaiki indeks maks, karena array_compare.reverse.each_with_indexmengembalikan indeks dari array terbalik .
Kode yang dihasilkan mungkin lebih panjang daripada di banyak jawaban lainnya, tetapi ini sederhana dan cepat:

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

LIHAT JUGA:

Array.include? relatif lambat. Selain itu, jika Anda hanya memerlukan hash untuk pencarian, pertimbangkan untuk menggunakan set:https://stackoverflow.com/a/411164/967621

Lebih lanjut tentang perbandingan kecepatan untuk array, set, dan hashes (dengan tolok ukur): Keuntungan Set di ruby

1 TeWu Aug 19 2020 at 18:12

Solusi paling berkinerja yang dapat saya hasilkan adalah:

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

Perhatikan bahwa argumennya set_inputadalah a Set, bukan Array. Mengonversi larik ke himpunan masuk akal, tetapi hanya jika Anda ingin memanggil find_last_indexberkali-kali dengan himpunan yang sama. Jika tidak proses konversi array untuk satu set ( to_set) membutuhkan lebih banyak waktu, dari yang Anda dapat memperoleh menggunakan Set#include?bukan sebuah Array#include?. Jadi jika Anda hanya ingin menggunakan find_last_indexsekali, Anda tidak boleh memanggil find_last_index(array_input.to_set, array_compare), tetapi gunakan versi ini yang tidak menggunakan set sama sekali:

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

Anda mungkin ingin melihat tolok ukur solusi berbeda untuk masalah ini.

user1934428 Aug 18 2020 at 18:32

Saya baru saja mengeksekusi (menyalin & menempel) kode Anda di irb , dan val"tiga" sesudahnya. Apakah Anda benar-benar memeriksanya valsetelah itu, yaitu

p val

? Ini adalah tangkapan layar transscript saya .