はじめに
株式会社シンシアでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。
※ シンシアにおける働き方の様子はこちら
弊社には年間100人程度の実務未経験の方に応募いただき、技術面接を実施しております。
その時に、Ruby で繰り返し処理について質問をいただいたので、記事にもまとめておきます。
Rubyには繰り返し処理(ループ)を書くための手段が非常に豊富に存在します。
この記事では、文字列 / 数値 / 配列 / ハッシュ(連想配列) / Range / 任意のオブジェクトに対して使えるループ構文やイテレータ、そして制御構文を一挙にまとめました。
さらに、実務での具体例を交えつつ、「どんな場面で使うと良いのか」も紹介していきます。
実務で見返せるようにしていただくととても便利だと思います!
初心者の方はもちろん、実務をある程度行っている方でも
案外知らないメソッドがあるかもしれません。
また、初心者の方向けに、よく使うものや特に理解しておいて欲しいものには
"⭐︎" をつけておくので必ずチェックしてください!
1. 文字列(String)のループ
1-1. each_char
文字列を1文字ずつ取り出します。
"Hello".each_char do |ch|
puts ch
end
# => "H", "e", "l", "l", "o"
使いどころ(実務での具体例)
- 入力バリデーション: 1文字ずつ適切に判定したい
- 暗号化/復号処理: 1文字ごとにASCIIコード変換などを行いたい
- UIの文字アニメーション: 一文字ずつ表示するエフェクトを実装
1-2. each_line
改行区切りで1行ずつ取得します。
multi_lines = "Hello\nWorld\nRuby"
multi_lines.each_line do |line|
puts line
end
# => "Hello", "World", "Ruby"
(改行(\n)は消えません。)
使いどころ(実務での具体例)
- ログファイルの解析: 1行ごとに読み込み、エラー抽出などを行う
- 設定ファイルの読み込み: 行単位で設定を解析・適用
- テキストインポート: CSVなどを行単位で処理する
1-3. each_byte
文字列のバイト値を順番に取り出します。
"ABC".each_byte do |b|
puts b
end
# => 65, 66, 67 (ASCIIコード)
使いどころ(実務での具体例)
- バイナリ解析: 画像やファイルのバイナリデータを1バイトずつ処理
- プロトコル通信: TCP/UDPレベルで独自のデータを扱う場合
- 暗号化ロジック: バイト単位でXORなどを行う
1-4. each_codepoint
文字コードポイント(Unicode)を取り出します。
"あいう".each_codepoint do |cp|
puts cp
end
# => 12354, 12356, 12358
使いどころ(実務での具体例)
- 多言語対応: マルチバイト文字(日本語など)を正しく扱いたい時
- 文字変換・正規化: 濁点や半角全角などの調整
- 絵文字など特殊文字の処理: 通常のバイト操作では崩れる可能性がある文字も安全に扱う
1-5. scan
正規表現にマッチする部分を抽出してブロックに渡します。
"abc123def456".scan(/\d+/) do |match|
puts match
end
# => "123", "456"
使いどころ(実務での具体例)
- テキストから数値抽出: 書類番号や顧客IDを文字列から拾う
- HTMLスクレイピング: タグや属性を正規表現で解析
- ログやメッセージ解析: 特定のパターンをマッチしてアラート検知
2. 数値(Integer)のループ
2-1. times
⭐︎
指定回数繰り返す。0
からカウントアップ。
3.times do |i|
puts i
end
# => 0, 1, 2
使いどころ(実務での具体例)
- 複数レコード作成: ダミーデータを指定数だけ生成するとき
- リトライ処理: 一定回数繰り返すロジック(例: APIリトライ)
- シンプルな繰り返し: 「○回だけ同じ処理」など
2-2. upto
数値を小さい方から大きい方へカウントアップしながら処理。
1.upto(3) do |num|
puts num
end
# => 1, 2, 3
使いどころ(実務での具体例)
- ページ送り処理: 1ページ目からNページ目まで順に処理
- ファイル命名: ファイル名に連番を付ける際のカウントアップ
- IDの自動発行: 最初から最後まで順にIDを割り振る
2-3. downto
upto
の逆でカウントダウンします。
3.downto(1) do |num|
puts num
end
# => 3, 2, 1
使いどころ(実務での具体例)
- タイマーのカウントダウン: 残り時間を計測
- リソース削減: 高値から順にチェックして途中で打ち切る場合
- 逆順表示: データを後ろから順に並べたいとき
2-4. step
増分(ステップ)を指定してカウントアップ/ダウン。
# 1から10まで2刻み
1.step(10, 2) do |n|
puts n
end
# => 1, 3, 5, 7, 9
使いどころ(実務での具体例)
- サンプリング: 大量データの中から一定間隔で抽出
- グラフ描画用: X軸やY軸の目盛を指定間隔で生成
- ループ負荷軽減: 全要素でなくステップ飛ばしで処理するとき
3. 配列(Array)のループ
Rubyの配列はEnumerable
モジュールをincludeしているため、下記の多くのメソッドが利用可能です。
3-1. each
⭐︎
要素を順番に取り出す。
[1,2,3].each do |num|
puts num
end
# => 1, 2, 3
使いどころ(実務での具体例)
- ユーザーリストの処理: 配列化したユーザーIDをループして処理
- DBテーブル行取得: 取得したレコードを1行ずつ処理
- 一括メール送信: 宛先リストをループしてメール送信
3-2. each_with_index
⭐︎
要素とインデックスを同時に取得。
["Ruby", "Python", "Go"].each_with_index do |lang, i|
puts "#{i}: #{lang}"
end
# => 0: Ruby
# 1: Python
# 2: Go
使いどころ(実務での具体例)
- 表示ランキング: インデックスを順位として表示
- リスト選択UI: インデックスを選択番号として扱う
- CSVのカラム出力: ヘッダと列番号を合わせる
3-3. map
/ collect
⭐︎
ブロックの戻り値を新しい配列として返す。
nums = [1, 2, 3]
squares = nums.map { |n| n * n }
# => [1, 4, 9]
使いどころ(実務での具体例)
- 型変換・フォーマット変換: 数字を文字列にするなど
- 計算処理: 数値のリストを一括で平方や割引価格に変換
- APIレスポンス整形: JSONで受け取った配列要素を加工して返す
3-4. select
/ reject
⭐︎
-
select
: 条件が真の要素を抽出 -
reject
: 条件が真の要素を除外
nums = [1,2,3,4,5,6]
even = nums.select { |n| n.even? } # => [2,4,6]
odd = nums.reject { |n| n.even? } # => [1,3,5]
使いどころ(実務での具体例)
- データのフィルタリング: 年齢20歳以上だけ抽出など
- 権限管理: 管理者アカウントだけ選別、または除外
- 稼働状況チェック: 稼働中のサーバーのみ抽出して監視
3-5. find
/ detect
⭐︎
条件を満たす最初の要素を返す。
nums = [10, 20, 30, 40]
result = nums.find { |n| n > 25 }
# => 30
使いどころ(実務での具体例)
- 最初にエラーが出た行を探す: ログ解析でエラー行を一つだけ特定
- 在庫チェック: 最初に在庫ありの商品を返す
- ユーザー検索: 複数条件に合うユーザーの中から先頭の1人だけ
3-6. find_all
⭐︎
条件を満たすすべての要素を抽出(select
と同じ動き)。
nums = [10, 20, 30, 40]
result = nums.find_all { |n| n > 25 }
# => [30, 40]
使いどころ(実務での具体例)
- 複数マッチの検索: 同じカテゴリーの商品をまとめて抽出
- フィルタリング: ログファイルから特定のタグ付き行を全取得
- 条件付き集計: ある期間のレコードをすべて取り出して計算
3-7. any?
/ all?
/ none?
/ one?
ブロック条件の一致度合いを真偽値で判定。
arr = [1, 3, 5]
arr.any? { |n| n.even? } # => false
arr.all? { |n| n.odd? } # => true
arr.none? { |n| n.even? } # => true
arr.one? { |n| n == 3 } # => true
使いどころ(実務での具体例)
- バリデーション: 値が一つでも不正ならNG, 全部正しければOKなど
- UI警告表示: 一つでも危険値があれば警告を出す
- リスト状態確認: 空き枠があるかどうか(any?)、全部使用中か(all?)
3-8. partition
ブロックが真の要素と偽の要素に2分割。
nums = [1,2,3,4,5,6]
even, odd = nums.partition { |n| n.even? }
# even => [2,4,6]
# odd => [1,3,5]
使いどころ(実務での具体例)
- 顧客をVIPと一般に仕分け: 条件により2つのリストに分けたい
- タグ分け: タグ付き/タグなしでデータを2分割
- 合否判定: 条件合格/条件不合格を同時に取得
3-9. group_by
ブロックの戻り値をキーにして、要素をハッシュで返す。
words = ["apple", "ant", "banana", "cat"]
grouped = words.group_by { |w| w[0] }
# => {"a"=>["apple","ant"], "b"=>["banana"], "c"=>["cat"]}
使いどころ(実務での具体例)
- グループ分け表示: イニシャルごとにユーザーを分類
- カテゴリ分け集計: 収支をカテゴリ別にグループ化
- サマリーレポート: 1日のログを時間帯ごとに分類
3-10. inject
/ reduce
要素を畳み込み、ひとつの値に集約。
nums = [1,2,3,4]
sum = nums.inject(0) { |acc, n| acc + n }
# => 10
使いどころ(実務での具体例)
- 集計処理: 合計金額や合算ポイントなどを算出
- ハッシュ生成: 配列からキーや値を加工してハッシュ化
- カスタムロジック: XORや論理積など、特殊な積算処理
3-11. each_with_object
ブロックに渡されたオブジェクトを加工しつつ、最終的に返す。
arr = ["apple", "banana", "cat"]
# 文字と文字数のハッシュを作る
result = arr.each_with_object({}) do |item, hash|
hash[item] = item.size
end
# => {"apple"=>5, "banana"=>6, "cat"=>3}
使いどころ(実務での具体例)
- 辞書(ハッシュ)作成: 配列の値をキーにしてサイズや属性を保存
- 複雑な統計情報: ブロック内で集計しながらハッシュに格納
- グループ別配列作成: ループしながらカテゴリごとの配列をつくる
3-12. chunk
/ chunk_while
-
chunk
: ブロックの戻り値が変わったタイミングで配列を区切る -
chunk_while
: ブロックが真の間、要素をまとめ続ける
nums = [1,1,2,2,2,3,1]
chunks = nums.chunk { |n| n }.to_a
# => [[1,[1,1]],[2,[2,2,2]],[3,[3]],[1,[1]]]
nums2 = [1,2,3,2,3,4,5]
chunked = nums2.chunk_while { |a,b| b > a }
chunked.each { |c| p c }
# => [1,2,3]
# [2,3,4,5]
使いどころ(実務での具体例)
- 状態変化の区切り: ステータスコードが変わる瞬間でグループ化
- 連続値のまとまり: 同じ数字や連続した数字をひとまとめにする
- ログ解析: エラーコードが続く区間などをまとめて分析
3-13. slice_when
/ slice_before
/ slice_after
複雑な条件で配列を分割する。
arr = [1,2,3,10,11,12,20]
sliced = arr.slice_when { |prev, curr| (curr - prev) >= 5 }
sliced.each { |sub| p sub }
# => [1,2,3]
# [10,11,12]
# [20]
使いどころ(実務での具体例)
- 不連続データの仕分け: 値の差が大きい部分で区切る
- 区切り文字を目印に: 「;」や「:」が出現したらスライスを分ける
- バッチ処理: 入庫日が変わったらスライスするなどの日付操作
3-14. each_slice(n)
/ each_cons(n)
-
each_slice(n)
: 要素をn個ずつ塊にして取り出す -
each_cons(n)
: 要素をn個ずつ1つずつずらして取り出す
arr = [1,2,3,4,5,6]
arr.each_slice(2) { |slice| p slice }
# => [1,2], [3,4], [5,6]
arr.each_cons(2) { |cons| p cons }
# => [1,2], [2,3], [3,4], [4,5], [5,6]
使いどころ(実務での具体例)
- 大規模処理の分割: 数千件のデータをまとめてn件ずつ処理
- ペア比較: 連続する2要素を比較して差分を取るなど
- ログをブロック単位で見る: 5行ずつまとめて解析
3-15. reverse_each
配列を末尾から先頭に向かって要素を取り出す。
arr = [1,2,3,4]
arr.reverse_each do |val|
puts val
end
# => 4, 3, 2, 1
使いどころ(実務での具体例)
- 最新データから処理: ログや履歴を後ろから読む
- スタックのような扱い: 最後に入れた要素から取り出したい
- 逆順アルゴリズム: 昇順で処理済みの場合などに逆順で再チェック
4. ハッシュ(Hash)のループ
RubyのHash
もEnumerable
をincludeしているため、each
, map
, select
などほぼすべてのイテレータが利用可能。
加えて、キーと値に特化したイテレータがあります。
4-1. each
⭐︎
キーと値を順番に取得。
person = { name: "Alice", age: 20 }
person.each do |k, v|
puts "#{k}: #{v}"
end
# => name: Alice
# age: 20
使いどころ(実務での具体例)
- 設定値のループ: 設定キーを読み込んで実行時に適用
- DBカラム名と値のペア処理: レコードをハッシュ化して保存
- JSONレスポンス解析: キーと値をひとつずつチェック
4-2. each_key
, each_value
, each_pair
h = { a: 1, b: 2, c: 3 }
h.each_key { |k| puts k } # => :a, :b, :c
h.each_value { |v| puts v } # => 1, 2, 3
h.each_pair { |k,v| puts "#{k}-#{v}" }
# => a-1, b-2, c-3
使いどころ(実務での具体例)
- キー一覧だけ表示: 翻訳辞書などで、存在するキーを確認
- 値だけ集計: ageの平均など値だけを計算
- キー-値セット操作: 既存のHashを別のHashにコピー・変換
4-3. transform_keys
, transform_values
ハッシュのキーや値を一括変換して新しいハッシュを返す。
h = { name: "bob", city: "Tokyo" }
new_h = h.transform_keys { |key| key.upcase }
# => {"NAME"=>"bob", "CITY"=>"Tokyo"}
new_h2 = h.transform_values { |val| val.upcase }
# => {:name=>"BOB", :city=>"TOKYO"}
使いどころ(実務での具体例)
- キーのフォーマット統一: APIで受け取ったキーをスネークケースに揃えるなど
- 値の暗号化/マスク: パスワードや秘匿情報を一括で変換
- キー・値の正規化: 全部小文字・全部大文字などで検索しやすくする
5. Range オブジェクトのループ
Range
オブジェクト(1..5
など)もEnumerable
をincludeしているので、each
やmap
などが利用可能です。
(1..5).each do |num|
puts num
end
# => 1, 2, 3, 4, 5
(1..10).step(2) do |n|
puts n
end
# => 1, 3, 5, 7, 9
使いどころ(実務での具体例)
- ページング処理: 1ページ目からnページ目までを順番に取得
- データ検証: 数字や文字の連続範囲を一括チェック
- シーケンス生成: 連番や文字列("a".."z")を自動生成
6. 制御構文 (言語仕様)
6-1. while / until
⭐︎
i = 0
while i < 3
puts i
i += 1
end
# => 0,1,2
j = 3
until j < 0
puts j
j -= 1
end
# => 3,2,1,0
使いどころ(実務での具体例)
- リアルタイム監視: ある条件が変わるまでループを続ける
- 待機処理: ユーザー入力待ちや外部APIの完了待ち
- 状態が変わるまで回す: フラグが立つまで継続処理
6-2. for
⭐︎
for n in [10, 20, 30]
puts n
end
# => 10,20,30
# (※ Rubyの`for`は内部的に`each`を呼んでいる)
使いどころ(実務での具体例)
-
他言語出身者向け:
for
に慣れている人が書きやすい - 簡易スクリプト: 小規模のスクリプトで短く書きたいとき
-
範囲を明示:
for i in 1..n
でループ範囲が分かりやすい
6-3. loop do ... end
⭐︎
count = 0
loop do
puts count
count += 1
break if count > 2
end
# => 0, 1, 2
使いどころ(実務での具体例)
- 無限ループが基本: サーバーのメインループなど、breakを入れるまで継続
- カスタム制御: 条件が複雑な抜け方をするループ
- イベント待ち: 特定のイベントが来るまで永久に回し続ける
6-4. begin ... end while/until
⭐︎
k = 0
begin
puts k
k += 1
end while k < 3
# => 0,1,2
使いどころ(実務での具体例)
- 最低1回実行必須: パスワード入力など、最初の1回は必ず表示
- ユーザー選択リピート: 一度操作してから、継続するか選ばせる
- 条件があとで決まる: 実行後に状態をチェックしたい処理
最後に
ここではRubyのループ処理を幅広く網羅してみました。
実際に実務ではあまり使わないものもあるので、実際に特殊な処理をしたいときなどに「こんなものもあったな...」と思い出せるくらいに眺めておくと良いかもしれません。
実務の具体例も参考に、ぜひ「状況に合ったループ処理」を使いこなして、読みやすくて保守しやすいコードを書いてみてください。