1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

第2章|今さら学ぶ「Rubyらしさ(Enumerable)」

1
Last updated at Posted at 2026-02-18

第2章|今さら学ぶ「Rubyらしさ(Enumerable)」

📚 シリーズ目次はこちら → 「今さら学ぶ」シリーズ — はじめに
🗺️ KnowledgeNoteの設計を確認 → 設計マップ

この章でわかること

  • each / map / select / reject / find の使い分け
  • 「ベルトコンベア」のたとえで掴むEnumerableの考え方
  • 破壊的メソッドと非破壊的メソッドの違い
  • メソッドチェーンで処理をつなげるテクニック
  • KnowledgeNoteのコードで見る「Rubyらしい書き方」

🏠 たとえ話で掴む「Enumerable」

第1章で、Arrayは「本棚」、Hashは「整理棚」と整理した。今回はその棚から中身を取り出して加工する方法、つまり 配列を効率よく処理する仕組み の話です。

ここでは 工場のベルトコンベア のイメージで考える。

ベルトコンベアの上を、製品(配列の要素)が1つずつ流れてくる。コンベアの途中には「検品係」や「加工係」がいて、流れてきた製品に対して決まった作業をする。

ベルトコンベア Rubyのメソッド やること
検品係が1つずつ確認する each 全要素に同じ処理を実行する
加工係が製品を変形する map 全要素を変換して新しい配列を作る
品質チェックで合格品だけ通す select 条件に合う要素だけ残す
不良品だけ取り除く reject 条件に合う要素を除外する
「これだ!」と1つだけ見つける find 条件に合う最初の1つを返す

Enumerableとは何か — 技術的な定義

Enumerable(イニューメラブル) は、Rubyが提供する モジュール (メソッドの集合体)です。selectmapfind などの便利なメソッドが50以上まとめられていて、ArrayやHashには最初から組み込まれている(include Enumerableされている)ため、特別な準備なしに使えます。

Enumerableのメソッドは内部的に each を土台にしている。つまり each さえ定義されたクラスにEnumerableをincludeすれば、selectmap も自動的に使えるようになる。この設計がRubyの柔軟さを支えています(→ 第3章のモジュールで詳しく扱います)。

大事なのは、 eachだけで全部やろうとしないこと。目的に合ったメソッドを選べると、コードが格段に読みやすくなります。


🔁 each — 「1つずつ確認する」基本の繰り返し

each は最も基本的なメソッドです。配列の要素を1つずつ取り出して、ブロック(do ... end{ } で囲んだ処理)を実行する。ブロックについての詳細は(→ 第4章で詳しく扱います)。

tags = ["Ruby", "Rails", "SQL"]

# eachで1つずつ表示する
tags.each do |tag|
  puts "タグ: #{tag}"
end
# => タグ: Ruby
# => タグ: Rails
# => タグ: SQL

each は「全員に同じ処理をする」ときに使う。ただし、 eachの中で新しい配列を作ろうとすると冗長になりがち です。第1章の最後に書いたコードがまさにそのパターンでした。

# eachで「公開済み記事のタイトル」を集める — やや冗長
published_titles = []
articles.each do |article|
  if article[:status] == "published"
    published_titles << article[:title]
  end
end

これをもっとスッキリ書けるのが、次の selectmap です。


🔍 select / reject — 「条件で絞り込む」

select — 合格品だけ通す

select は、条件に合う要素だけを残して新しい配列を返す。品質チェックの合格品だけをコンベアの先に流すイメージです。

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 偶数だけを選ぶ
evens = numbers.select { |n| n.even? }
puts evens   # => [2, 4, 6, 8, 10]

ブロックの中の条件が true になった要素だけが残る。

reject — 不良品を取り除く

rejectselect の逆で、条件に合う要素を 除外 する。

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 偶数を除外する(= 奇数だけ残す)
odds = numbers.reject { |n| n.even? }
puts odds   # => [1, 3, 5, 7, 9]

「〜を除きたい」ときは reject、「〜だけ残したい」ときは select


🔄 map — 「全部を変換する」

map は、配列の全要素を変換して新しい配列を作る。加工係が製品を1つずつ別の形に変えていくイメージです。

names = ["tanaka", "suzuki", "yamada"]

# 全員の名前を大文字に変換する
upper_names = names.map { |name| name.upcase }
puts upper_names   # => ["TANAKA", "SUZUKI", "YAMADA"]

元の配列 names は変わらない。map新しい配列を返す のがポイントです。

each と map の決定的な違い

tags = ["Ruby", "Rails", "SQL"]

# each — 戻り値は元の配列そのまま(処理結果は返さない)
result_each = tags.each { |tag| tag.downcase }
puts result_each   # => ["Ruby", "Rails", "SQL"](元のまま!)

# map — 戻り値は変換後の新しい配列
result_map = tags.map { |tag| tag.downcase }
puts result_map    # => ["ruby", "rails", "sql"](変換された!)

each は「処理を実行するだけ」で結果の配列を返さない。「変換した結果を使いたい」なら map を使います。


🎯 find — 「最初の1つを見つける」

find は、条件に合う 最初の1つ だけを返す。見つかった瞬間に探索を終了するので、全要素を調べる必要がないときに効率的です。

articles = [
  { id: 1, title: "Ruby入門",   status: "draft" },
  { id: 2, title: "Rails基礎",  status: "published" },
  { id: 3, title: "SQL完全理解", status: "published" }
]

# 最初に見つかった公開済み記事を取得
first_published = articles.find { |a| a[:status] == "published" }
puts first_published[:title]   # => "Rails基礎"

select との違いは、select が「全部集める(配列を返す)」のに対し、find は「最初の1つだけ(単体を返す)」という点です。


⛓️ メソッドチェーン — ベルトコンベアをつなげる

ここまでのメソッドは つなげて使える のが大きな強み。ベルトコンベアの先にさらにコンベアを接続するイメージです。

第1章で書いた冗長なコードを、メソッドチェーンで書き直してみる。

articles = [
  { title: "Ruby入門",     status: "published" },
  { title: "Rails基礎",    status: "draft" },
  { title: "SQL完全理解",   status: "published" },
  { title: "Git入門",      status: "draft" }
]

# before: eachで書いた場合(第1章の書き方)
published_titles = []
articles.each do |article|
  if article[:status] == "published"
    published_titles << article[:title]
  end
end

# after: select + map で書いた場合(Rubyらしい書き方)
published_titles = articles
  .select { |a| a[:status] == "published" }  # 公開済みだけ残す
  .map { |a| a[:title] }                     # タイトルだけ取り出す

puts published_titles   # => ["Ruby入門", "SQL完全理解"]

6行が2行になった。しかも読み方が自然で、「公開済みを選んで(select)→ タイトルを取り出す(map)」と、日本語の順番どおりに読めます。


⚠️ 破壊的メソッドと非破壊的メソッド

Rubyには、 元のデータを変更するメソッド(破壊的)元のデータを変えずに新しいデータを返すメソッド(非破壊的) の2種類がある。

これを 原本とコピー にたとえると:

  • 非破壊的メソッド = 原本はそのまま残して、 コピーに修正を加える
  • 破壊的メソッド = 原本そのものに直接修正を加える (元に戻せない)
tags = ["Ruby", "Rails", "SQL"]

# 非破壊的メソッド — 元の配列は変わらない
sorted = tags.sort
puts sorted   # => ["Rails", "Ruby", "SQL"](ソート済みのコピー)
puts tags     # => ["Ruby", "Rails", "SQL"](元のまま!)

# 破壊的メソッド(!がつく)— 元の配列が変わる
tags.sort!
puts tags     # => ["Rails", "Ruby", "SQL"](元が変わった!)

見分け方のルール

Rubyでは、破壊的メソッドの多くに !(ビックリマーク) がついている。

# 非破壊的(コピーを返す)
tags.map { |t| t.upcase }     # tagsは変わらない
tags.select { |t| t.size > 3 } # tagsは変わらない
tags.sort                      # tagsは変わらない

# 破壊的(元を変える)
tags.map! { |t| t.upcase }    # tags自体が変わる
tags.select! { |t| t.size > 3} # tags自体が変わる
tags.sort!                     # tags自体が変わる

⚠️ ただし、<<(push)や delete のように、! がなくても破壊的なメソッドもある。「! がなければ安全」とは限りません。

基本的には 非破壊的メソッドを使うのが安全 です。元のデータを変えてしまうと、他の場所で使っているときに予期しないバグを生みます。


🛠️ KnowledgeNoteでの具体例

KnowledgeNoteの記事データを使った実践的な例です。

# 記事一覧から、条件に合うデータを抽出する
articles = [
  { title: "Ruby入門",       status: "published", likes: 15, tags: ["Ruby"] },
  { title: "Rails基礎",      status: "draft",     likes: 0,  tags: ["Rails"] },
  { title: "SQL完全理解",     status: "published", likes: 42, tags: ["SQL", "DB"] },
  { title: "Git入門",        status: "published", likes: 8,  tags: ["Git"] },
  { title: "Docker入門",     status: "draft",     likes: 0,  tags: ["Docker"] }
]

# 公開済み記事の中で、いいねが10以上のタイトルを取得
popular_titles = articles
  .select { |a| a[:status] == "published" }  # 公開済みだけ
  .select { |a| a[:likes] >= 10 }            # いいね10以上
  .map { |a| a[:title] }                     # タイトルを取り出す
# => ["Ruby入門", "SQL完全理解"]

# 全記事のタグを1つの配列にまとめる(flattenで平坦化)
all_tags = articles
  .map { |a| a[:tags] }   # => [["Ruby"], ["Rails"], ["SQL", "DB"], ...]
  .flatten                 # => ["Ruby", "Rails", "SQL", "DB", "Git", "Docker"]
  .uniq                    # => 重複を除去
# => ["Ruby", "Rails", "SQL", "DB", "Git", "Docker"]

Railsでは、このような操作をActiveRecordの スコープ (→ 第16章)やクエリメソッドで行うが、考え方は同じ。「絞り込んで → 変換して → 取り出す」という流れは、Ruby全体を通して使える基本パターンです。


📊 使い分け早見表

やりたいこと メソッド 戻り値
全要素に処理を実行したい each 元の配列
全要素を変換したい map 新しい配列
条件に合うものだけ残したい select 新しい配列
条件に合うものを除外したい reject 新しい配列
条件に合う最初の1つを見つけたい find 1つの要素(or nil)
全要素を1つの値にまとめたい reduce 1つの値
条件を満たすか全体で判定したい any? / all? / none? true / false

💼 面接で聞かれたら?

Q:each と map の違いを説明してください。

each は配列の全要素に処理を実行しますが、戻り値は元の配列そのままです。一方 map は全要素を変換した新しい配列を返します。変換結果を使いたいときは map、単に処理を実行するだけなら each を使い分けます。」

深掘りされたら:

  • 「破壊的メソッドとは?」→ 元のオブジェクトを直接変更するメソッド。sort!map! のように末尾に ! がつくものが多いが、<<delete のように ! がなくても破壊的なものもある。
  • 「select と find の違いは?」→ select は条件に合う全要素を配列で返す。find は条件に合う最初の1つだけを返す。

🔗 もっと深く知りたい人へ(1次情報リンク)


まとめ

  • ✅ Enumerableは「ベルトコンベア」。配列の要素を1つずつ処理するメソッド群をまとめたモジュール
  • each は処理の実行、map は変換、select は絞り込み、find は1つ探す
  • ✅ メソッドチェーンで処理をつなげると、Rubyらしく簡潔に書ける
  • ✅ 破壊的メソッド(!付き)は元のデータを変える。基本は非破壊的メソッドを使う
  • ✅ 「eachだけで全部やる」のではなく、目的に合ったメソッドを選ぶのがRubyらしさ

📚 シリーズ目次:「今さら学ぶ」シリーズ — はじめに

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?