Ruby-配列を比較し、条件に基づいてインデックスを取得します

Aug 18 2020

私は2つの配列を持っています

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

ただし、valは設定されません。

回答

1 CarySwoveland Aug 19 2020 at 02:30

1つは書くことができます

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

Array#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

配列、セット、およびハッシュの速度比較の詳細(ベンチマークを使用):Rubyでのセットの利点

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はでありSet、ではないことに注意してくださいArray。配列をセットに変換することは理にかなっていますfind_last_indexが、同じセットで何度も呼び出す場合に限ります。そうしないと、配列をセット(to_set)に変換するプロセスに、のSet#include?代わりにを使用して得られるよりも多くの時間がかかりますArray#include?。したがって、find_last_index1回だけ使用する場合は、を呼び出すの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その後は「3」になりました。valその後、実際に検査しましたか?

p val

?これが私のトランスクリプトのスクリーンショットです。