Enumerable#select
(Enumerable#find_all
)ならば要素配列が返ってきますが、位置(index)だけ返ってくるメソッドが欲しかったので、モンキーパッチを書きました。
Enumerable#find
に対するEnumerable#select
と同じ関係で、Enumerable#find_index
に対するEnumerable#select_index
というメソッドです。
ついでにEnumerable#select
に対するEnumerable#reject
と同じ関係で、Enumerable#select_index
に対するEnumerable#reject_index
も作りました。
Ruby 1.9以上で使えます。多分1.8でも使えるんじゃないかとおもいます。
-
Enumerable#select_index
:各要素に対してブロックを評価した値が真であった位置を全て含む配列を返します。エイリアスとしてEnumerable#find_all_index
を設定しています。 -
Enumerable#reject_index
:各要素に対してブロックを評価した値が真であった位置を全て含む配列を返します。
#モンキーパッチ
module Enumerable
def select_index
return to_enum(__method__) unless block_given?
values = []
self.each_with_index{ |item, i| values << i if yield(item) }
values
end
alias :find_all_index :select_index
def reject_index
return to_enum(__method__) unless block_given?
values = []
self.each_with_index{ |item, i| values << i unless yield(item) }
values
end
end
#使用例
a = (0..19).map{ rand(100) }
# => [29, 73, 39, 71, 4, 71, 43, 65, 61, 21, 53, 62, 47, 72, 78, 96, 1, 2, 44, 70]
a.select_index { |item| item > 70 }
# => [1, 3, 5, 13, 14, 15]
a.reject_index { |item| item > 70 }
# => [0, 2, 4, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18, 19]
s_idx = a.select_index
# => #<Enumerator: ...>
s_idx.each { |item| item > 70 }
# => [1, 3, 5, 13, 14, 15]
r_idx = a.reject_index
# => #<Enumerator: ...>
r_idx.each { |item| item > 70 }
# => [0, 2, 4, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18, 19]
#参考サイト
-
select_index monkeypatch 望んでいる
select_index
ではありませんでしたが、構成を参考にしました。 - Enumerator とブロックの省略 - まめめも ブロックを省略した場合の処理を参考にしました。
# おまじない
return to_enum(:leapfrog) unless block_given?
-
Ruby - ブロックを与えない場合にEnumeratorを返すメソッドを作る - Qiita
Kernel.#__method__
を参考にしました。
ブロックが指定されなかったときは、自身のメソッド名を引数にしてenum_forでEnumeratorを返してやればよいわけですね。
※Kernel.#__method__は現在のメソッド名を返します。