記事内にはプロモーションが含まれています

【Ruby】each_with_indexの使い方は?1から始める方法やwith_indexとの違いも解説

【Ruby】each_with_indexの使い方は?1から始める方法やwith_indexとの違いも解説 Ruby

Rubyで配列(Array)やハッシュ(Hash)をループ処理する際、要素の中身だけでなく「今何番目の要素を処理しているか(インデックス)」も同時に取得したい場面は頻繁にあります。

そんな時に便利なのが each_with_index メソッドです。
これを使えば、自分でカウンター変数を用意してインクリメントするような面倒な記述から解放されます。

しかし、実務では「インデックスを0からではなく1から始めたい」「map メソッドでもインデックスを使いたい」といった応用的な要望も出てくるでしょう。

実は、each_with_index よりも each.with_index を使った方がスマートに書けるケースも多いのです。

この記事では、Rubyの each_with_index の基本から、インデックスの開始番号を調整する方法、そして似ているメソッド with_index との使い分けまでを、最新トレンドに合わせて徹底解説します。

【本記事の信頼性】
プロフィール
執筆者:マヒロ
  • 執筆者は元エンジニア
  • SES⇒大手の社内SE⇒独立
  • 現在はこじんまりとしたプログラミングスクールを運営
  • モットーは「利他の精神」

each_with_indexメソッドとは?基本の使い方

each_with_index は、Enumerableモジュールで定義されているメソッドの一つです。

配列などの要素を順番に取り出しながら、同時にその要素のインデックス(0から始まる連番)もブロック変数として渡してくれます。

配列でインデックスを取得する基本形

使い方は通常の each とほぼ同じで、ブロック引数が2つになる点が特徴です。

fruits = ["apple", "banana", "cherry"]

# |要素, インデックス| の順で受け取る
fruits.each_with_index do |fruit, i|
  puts "#{i}番目のフルーツ: #{fruit}"
end

実行結果は以下の通りです。

0番目のフルーツ: apple
1番目のフルーツ: banana
2番目のフルーツ: cherry

ポイントは以下の通りです。

  • ブロック引数の1つ目(fruit)に要素の値が入ります。
  • ブロック引数の2つ目(i)にインデックス番号が入ります。
  • インデックスは必ず 0 から始まります。

インデックスを「1」から始めたい場合の対処法

ランキング表示やログ出力など、インデックスを「0」ではなく「1」からスタートさせたいケースは多々あります。

each_with_index を使う場合と、より推奨される each.with_index を使う場合の2パターンを見てみましょう。

1. each_with_indexの中で計算する(従来の方法)

each_with_index 自体には開始番号を指定するオプションはありません。
そのため、ブロック内でインデックスに + 1 をして表示する必要があります。

fruits = ["apple", "banana", "cherry"]

fruits.each_with_index do |fruit, i|
  # 表示するときに 1 を足す
  puts "#{i + 1}番目: #{fruit}"
end

この方法はシンプルですが、インデックスを使う箇所すべてで + 1 を書く必要があり、少し手間がかかります。

2. each.with_index(1) を使う(推奨される方法)

Rubyには with_index というメソッドもあり、こちらは引数で「開始番号(オフセット)」を指定できます。 each メソッドをブロックなしで呼び出すと Enumerator オブジェクトが返るため、それに with_index をチェーンさせる書き方です。

fruits = ["apple", "banana", "cherry"]

# 引数に 1 を渡すと、インデックスが 1 から始まる
fruits.each.with_index(1) do |fruit, i|
  puts "#{i}番目: #{fruit}"
end

実行結果は以下の通りです。

1番目: apple
2番目: banana
3番目: cherry

この書き方のメリットは、ブロック内での + 1 計算が不要になってコードが読みやすくなることと、「1から始めたい」という意図が明確に伝わることです。

each_with_index と with_index の違い・使い分け

「each_with_index と with_index のどちらを使えばいいの?」と迷うかもしれませんが、それぞれの特性を理解して使い分けるのがベストです。

each_with_index の特徴

メリット
メソッド名が具体的で、「ループしながらインデックスを取る」という意図が分かりやすい。

デメリット
開始番号の指定ができない。map など他のメソッドと組み合わせにくい。

使いどころ
単純に0から始まるループ処理を行いたい場合。

with_index の特徴

メリット
開始番号を指定できる。mapselect などの Enumerator を返すメソッドにも後付けできる。

デメリット
each をブロックなしで呼び出す必要があるため、少し記述が長くなる(each.with_index)。

使いどころ
1から始めたい場合や、each 以外のメソッドでインデックスを使いたい場合。

応用例として、mapメソッドでインデックスを使うという方法もあります。
map メソッドには map_with_index というメソッドは存在しません。
しかし、with_index を使えば以下のように書くことができます。

fruits = ["apple", "banana", "cherry"]

# インデックス付きの文字列配列を作成
result = fruits.map.with_index(1) do |fruit, i|
  "No.#{i} #{fruit}"
end

p result
# => ["No.1 apple", "No.2 banana", "No.3 cherry"]

このように、柔軟性においては with_index の方が優れています

ハッシュ(Hash)でインデックス付きループを行う

ハッシュに対しても each_with_index を使用することができます。
ただし、ブロック変数の受け取り方に少し注意が必要です。

ハッシュでの書き方

ハッシュの場合、要素(キーと値のペア)が配列として第1引数に渡されます。

scores = { math: 80, english: 90, science: 75 }

scores.each_with_index do |(subject, score), i|
  puts "#{i}: #{subject}は#{score}点"
end

実行結果は以下の通りです。

0: mathは80点
1: englishは90点
2: scienceは75点

ポイントは、ブロック引数を (key, value), i のように括弧で囲むことで、キーと値を個別に受け取ることができる点です。
括弧を省略して |item, i| とすると、item[:math, 80] という配列が入ります。

each_slice など他のメソッドと組み合わせる応用

大量のデータを扱う際、each_slice を使って分割処理を行うことがありますが、この場合もインデックスを取得したいことがあります。

each_slice と with_index の組み合わせ

each_slice もブロックなしで呼び出すと Enumerator を返すため、with_index を繋げることができます。

users = ("A".."G").to_a
# => ["A", "B", "C", "D", "E", "F", "G"]

# 3つずつに分割しつつ、グループ番号を振る
users.each_slice(3).with_index(1) do |group, i|
  puts "グループ#{i}: #{group.join(', ')}"
end

実行結果は以下の通りです。

グループ1: A, B, C
グループ2: D, E, F
グループ3: G

このように、with_index はあらゆるイテレータメソッドの強力な味方になります。

Rubyのスキルを活かして年収を上げる方法

以上、each_with_indexの使い方などについて解説してきました。

なお、Rubyのスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。

Rubyエンジニアの年収や単価は高い傾向にあるため、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。

なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。

今すぐ転職する気がなくとも、とりあえず転職エージェントに無料登録しておくだけで、スカウトが届いたり、思わぬ好待遇の求人情報が送られてきたりするというメリットがあります。

併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなRubyの案件を探しやすくなります。

転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。