Ruby - เปรียบเทียบอาร์เรย์และรับดัชนีตามเงื่อนไข

Aug 18 2020

ฉันมีสองอาร์เรย์

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

ฉันต้องการแยกดัชนี 'สูงสุด' จากอาร์เรย์ array_compare หากมีค่าอยู่ในอาร์เรย์อินพุต เอาท์พุทที่ต้องการ2เป็นthreeอยู่ในอาร์เรย์การป้อนข้อมูลและcompareอาร์เรย์

ฉันพยายามแล้ว

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

แต่ไม่ได้ตั้งค่าวาล

คำตอบ

1 CarySwoveland Aug 19 2020 at 02:30

หนึ่งสามารถเขียน

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

แต่ต้องใช้การค้นหาเชิงเส้นarray_inputสำหรับแต่ละองค์ประกอบของarray_compare(เริ่มต้นด้วยสุดท้าย) จนกว่าจะพบรายการที่ตรงกัน ดีกว่าดังต่อไปนี้

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

ขั้นตอนมีดังนี้

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

ดูArray # & . โปรดทราบว่า "ลำดับจะถูกเก็บรักษาไว้จากอาร์เรย์เดิม [ array_compare]" การดำเนินการแบบครั้งเดียวนี้จะรวดเร็วมากเมื่อมีการใช้งานใน C.

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

ดูอาร์เรย์ # rindex

2 iGian Aug 18 2020 at 22:14

ถ้าฉันเข้าใจถูกต้อง

แยกดัชนี 'สูงสุด' จากอาร์เรย์ array_compare หากค่ามีอยู่ในอาร์เรย์อินพุต

นี่อาจเป็นตัวเลือก:

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

ถ้าarray_compare = %w[one two three four five three]มันกลับ5มา

2 TimurShtatland Aug 18 2020 at 23:18

แปลงอาร์เรย์ที่ใช้สำหรับการค้นหาเป็นชุดเพื่อให้ค้นหาได้เร็วขึ้น
วนซ้ำจากจุดสิ้นสุดของอาร์เรย์ที่คุณกำลังค้นหาดัชนีสูงสุด (ตามที่คุณกำลังทำอย่างถูกต้อง) และเพื่อความเร็ว โซลูชันที่วนซ้ำจากจุดเริ่มต้นของอาร์เรย์และเลือกดัชนีสูงสุดมักจะช้าลงเนื่องจากการค้นหาที่ไร้ประโยชน์ทั้งหมดจนกว่าจะพบองค์ประกอบที่ตรงกันล่าสุด วิธีการด้านล่างหยุดอย่างรวดเร็ว - ในการแข่งขันครั้งแรกที่ประสบความสำเร็จ
สุดท้ายแก้ไขดัชนีสูงสุดเนื่องจากarray_compare.reverse.each_with_indexส่งคืนดัชนีของอาร์เรย์ที่กลับรายการ
รหัสผลลัพธ์อาจยาวกว่าในหลาย ๆ คำตอบ แต่ทั้งง่ายและรวดเร็ว:

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

ดูสิ่งนี้ด้วย:

Array.include? ค่อนข้างช้า นอกจากนี้หากคุณต้องการแฮชสำหรับการค้นหาเท่านั้นให้พิจารณาใช้ชุด:https://stackoverflow.com/a/411164/967621

ข้อมูลเพิ่มเติมเกี่ยวกับการเปรียบเทียบความเร็วสำหรับอาร์เรย์ชุดและแฮช (พร้อมเกณฑ์มาตรฐาน): ข้อดีของการตั้งค่าในทับทิม

1 TeWu Aug 19 2020 at 18:12

วิธีแก้ปัญหาที่มีประสิทธิภาพมากที่สุดที่ฉันสามารถทำได้คือ:

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

โปรดทราบว่าอาร์กิวเมนต์set_inputคือ a Setไม่ใช่Array. การแปลงอาร์เรย์เป็นชุดนั้นเหมาะสม แต่ถ้าคุณต้องการเรียกfind_last_indexหลาย ๆ ครั้งด้วยชุดเดียวกัน มิฉะนั้นกระบวนการแปลงอาร์เรย์เป็น set ( to_set) จะใช้เวลานานกว่าที่คุณจะได้รับโดยใช้ a Set#include?แทนArray#include?. ดังนั้นหากคุณต้องการใช้find_last_indexเพียงครั้งเดียวคุณไม่ควรโทรfind_last_index(array_input.to_set, array_compare)แต่ใช้เวอร์ชันนี้ที่ไม่ใช้ชุดเลย:

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

คุณอาจต้องการดูเกณฑ์มาตรฐานของวิธีแก้ปัญหาต่างๆสำหรับปัญหานี้

user1934428 Aug 18 2020 at 18:32

ฉันเพิ่งดำเนินการ (คัดลอกและวาง) รหัสของคุณในirbและvalหลังจากนั้นเป็น "สาม" valหลังจากนั้นคุณตรวจสอบจริงหรือไม่เช่น

p val

เหรอ? นี่คือภาพหน้าจอของ transscript