環境 : Ruby 2.7.1
リファレンスマニュアル:
例えば、「各要素が0と1のみから成る配列から、1であるインデックスを探して何か処理する」ことを考える。探すだけなら each_with_index
などで可能だが、元の配列を書き換える(続きの探索に影響しうる)など複雑な処理である場合はループ文で地道に頑張る必要がある。
Rubyの場合はインデックスをループで回さなくても Array#index
で位置を特定できる。しかしこれには欠点があり、前回の続きから探索するということができない。
seq = [1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1]
i = -1
while (i = seq.index(1, i + 1))
# i が必要な複雑な処理
p i
end
#=> ArgumentError (wrong number of arguments (given 2, expected 0..1))
でも文字列の場合はできる。
seq = [1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1].map(&:chr).join
i = -1
while (i = seq.index(1.chr, i + 1))
# i が必要な複雑な処理
p i
end
#=> 0 2 4 5 6 7 11 14
逆順に探索する #rindex
も同じ。
配列を文字列に変えて #index
で探索する場合は以下の特徴がある。
- 利点
- (上で述べた通り)途中から探索できる
- 要素をまたぐ条件指定が簡単にできる:固定文字列または正規表現
- 欠点
- 要素の種類が非常に限られる
- 文字そのもの、または文字コードの範囲内の整数1
- 数値の場合は文字と変換する手間も発生
- ブロックを渡せないので複雑な条件を指定できない(数値が偶数である、など)
- 要素の種類が非常に限られる
-
Unicodeのサロゲートペアの領域のように、ある途中の範囲の数値が文字に変換できないという可能性にも注意 →
0xD800.chr('UTF-8')
↩