nekoTheShadow’s diary

技術ブログとして始めたはずが、読書&愚痴ブログになりました(´・ω・`)

rubyのwith_indexは便利。

mapは各要素に対してブロックを評価した結果の配列を返す、便利なメソッドですが、今日はその勉強中に、評価の対象としてレシーバのインデックスを利用したいとなりました。

nums = [1,2,3]
multipled_nums = []
nums.each_with_index do |num,idx|
  multipled_nums << num * (idx+1)
end
p multipled_nums #=> [1,4,9]

例がよくないのですが、要するに上のようなことをmapでやりたいのです。
そこで、いろいろ調べていると、とあるメソッドに行きつきました。
Enumerator#with_indexです。
説明文に曰く、

生成時のパラメータに従って、要素にインデックスを添えて繰り返します。 インデックスは offset から始まります。ブロックを指定した場合の戻り値は生成時に指定したレシーバ自身です。

とのことなので、これが利用できそうです。

nums = [1,2,3]
p nums.map.with_index(1){|num,idx| num * idx}
#=> [1,4,9]

よしよしできました。

上の例でも利用していますが、rubyの有名なメソッドのひとつにeach_with_indexがあります。
ブロックに要素とインデックスを渡してくれるので、便利といえば間違いなく便利なのですが……
個人的にインデックスが0から始まることが不満だったりします。
もちろん、0から始まった方が便利な時もありますが、1から始めたいというときも間違いなくあるわけです。
その点、with_indexは優秀ですね。
引数で指定した数字が始点になるわけですから。

nums = [1,2,3]
nums.each.with_index(1) do |num,idx|
  p {idx:idx, num:num}
end
#=>{idx:1, num:1}
#  {idx:2, num:2}
#  {idx:3, num:3}

それにしても、あげる例がよくないですね。
実際に利用したものをそのままブログに書くわけにもいかないので、難しいところです。