最終更新日:

この記事では、

  • RubyでのArray操作をもっと効率的に行いたい
  • シンプルで簡潔なコードを書いてみたい
  • eachメソッドとmapメソッドの違いを明確に理解したい

という悩みを抱えている向けに、

  • mapメソッドの基本情報と使い方
  • mapメソッドの応用的な使い方と例
  • mapメソッドとeachメソッドの比較

についてRailsエンジニアである私が解説していきたいと思います。

Rubyに関して言うと、mapメソッドはほぼマストで使えた方がよいメソッドになるので、ぜひ使えるようになりましょう。特にeachで冗長に書かざるを得ない状態で、mapはかなり綺麗にかけるのでおすすめです。

著者:

DAI
株式会社ワークスアプリケーションズにてQAエンジニア→株式会社AidemyにてAIプログラミングスクールのマーケティングを担当→キャリアコーチングサービスのパイオニアであるポジウィル株式会社にCMO就任→株式会社インディバースを創業。
IT系キャリアに関して情報発信しているDAINOTEを運営。自身も自社プロダクトであるMedia Analyticsの開発をRuby on Railsで行うWebエンジニアである。本業はWebマーケター。最近は生成AI系の開発にどハマり中。著書は独学プログラマーのためのAIアプリ開発がわかる本 。詳細は運営者情報をご覧ください。

mapメソッド:要素に対してiterationを実行して、配列で返すメソッド

Rubyでは、配列(Array)やハッシュ(Hash)の各要素に対して一定の処理を行い、その結果を新たな配列として返す方法としてmapメソッドがよく使用されます。mapメソッドは、配列の各要素に対してブロック内の処理を適用した結果を集めて、新しい配列を作ります。このメソッドは非常に便利で、Rubyで配列やハッシュを扱う際には頻繁に用いられるメソッドの一つです。

numbers = [1, 2, 3, 4, 5]
squared_numbers = numbers.map { |number| number ** 2 }
puts squared_numbers
# 結果: [1, 4, 9, 16, 25]

mapメソッドは、コードを簡潔に書けるだけでなく、コードの意図が明確になり読みやすくなる利点があります。

mapメソッドの基本的な使い方

mapメソッドを用いる基本的な形式は、配列やハッシュに対して.mapを呼び出し、その後ろにブロック({})を記述します。このブロック内で、各要素に対する処理を記述します。最終的に、このブロックの処理結果を元にした新しい配列が返されます。

例えば、次のコードでは、各要素の2倍を計算して新しい配列を作る例を示しています。

numbers = [1, 2, 3, 4, 5]
doubled_numbers = numbers.map { |number| number * 2 }
puts doubled_numbers
# 結果: [2, 4, 6, 8, 10]
DAI
もちろん、ブロックではなく、each do でも同じように書くこともできますよ!
numbers = [1, 2, 3, 4, 5]doubled_numbers = numbers.each do |number| 
   number * 2 
end
puts doubled_numbers
# 結果: [2, 4, 6, 8, 10]

mapメソッドが便利な場面:eachメソッドで配列に追加する処理を簡単に書ける

mapメソッドは、繰り返し処理をした結果を配列で受け取りたい時に便利です。

eachメソッドも配列の各要素に対して処理を行いますが、eachは各要素に対する処理の結果を集めて新しい配列を返すことはありません。

代わりに、もとの配列自体を変更せずに、単に各要素に対して指定したブロックの処理を実行します。

そのため、新しい配列を作成したい場合はmapメソッドの使用が適しています。

numbers = [1, 2, 3, 4, 5]
doubled_numbers = []
numbers.each { |number| doubled_numbers << number * 2 }
puts doubled_numbers
# 結果: [2, 4, 6, 8, 10]

上記のeachメソッドの例でも同じ結果が得られますが、mapメソッドを使う方がよりシンプルで直接的です。

関連:【Ruby】eachメソッドの使い方の基礎から応用まで現役エンジニアが解説します

【Ruby】eachメソッドの使い方の基礎から応用まで現役エンジニアが解説します

mapメソッドとcollectメソッドの関係: mapメソッドのエイリアス(同名です)

collectメソッドは、Rubyでmapメソッドと同じ役割を果たします。

実は、collectmapは互換性があり、どちらも配列の各要素に対してブロック内の処理を適用し、その結果を新しい配列として返します。

この2つのメソッドは内部的には同じ動作をするため、使用するメソッドは好みやプロジェクト内のコーディング規約に依存します。

例えば以下のコードでは、mapメソッドとcollectメソッドが同じ結果を返すことを示しています。

numbers = [1, 2, 3, 4, 5]

squared_numbers_map = numbers.map { |number| number ** 2 }
puts squared_numbers_map
# 結果: [1, 4, 9, 16, 25]

squared_numbers_collect = numbers.collect { |number| number ** 2 }
puts squared_numbers_collect
# 結果: [1, 4, 9, 16, 25]

mapメソッドの省略した書き方:symbol.to_procを使った省略形

Rubyでは、ブロックを使うメソッドに対して省略した記述法がよく用いられます。

特に、mapメソッドを使用する際には、この省略形が便利です。省略形を使うと、コードがさらに簡潔になり、読みやすくなります。

numbers = [1, 2, 3, 4, 5]
# ブロックを使わずに:symbol.to_procを使った省略形
squared_numbers = numbers.map(&:to_s)
puts squared_numbers
# 結果: ["1", "2", "3", "4", "5"]

上記のコードでは、to_sメソッドが各要素に対して呼び出され、数字を文字列に変換しています。

この省略形は、メソッド呼び出しが各要素に対して単一で、引数が不要な場合に特に有効です。

Hashでmapメソッドを使う方法

mapメソッドは、配列だけでなくハッシュに対しても使用することができます。

ハッシュを使用する場合、ブロック変数はキーと値のペアとして取り扱われます。

DAI
下記のkeyでは、countryがkey, capitalがvalueとして繰り返し処理がされています
capitals = { japan: 'Tokyo', france: 'Paris', italy: 'Rome' }
# キーを大文字に変換する
upcased_capitals = capitals.map { |country, capital| [country.to_s.upcase, capital] }.to_h
puts upcased_capitals
# 結果: {"JAPAN"=>"Tokyo", "FRANCE"=>"Paris", "ITALY"=>"Rome"}

このコードでは、ハッシュの各要素(国とその首都)に対して処理を行い、国名を大文字に変換しています。

最後にto_hメソッドを用いて、配列の配列をハッシュに変換しています。

mapメソッドとmap!メソッドの違いは?

mapメソッドには破壊的なバリエーションであるmap!メソッドも存在します。

map!メソッドは、元の配列自体を変更して、新しい値で更新します。これに対し、mapメソッドは元の配列を変更せず、新しい配列を作成します。

numbers = [1, 2, 3, 4, 5]
numbers.map! { |number| number ** 2 }
puts numbers
# 結果: [1, 4, 9, 16, 25]

map!メソッドを使用する際には、元の配列が変更されることを意識する必要があります。状況に応じて、mapメソッドとmap!メソッドを適切に選択してください。

インデックス付きで操作するmap.with_indexメソッドの活用

map.with_indexメソッドを使用すると、ブロック内で各要素のインデックスも扱うことができます。これにより、要素自体だけでなくその位置情報を利用した処理が可能になります。

# map.with_indexメソッドの使用例:
fruits = ['apple', 'banana', 'cherry']
capitalized_fruits_with_index = fruits.map.with_index { |fruit, index| [index, fruit.capitalize] }.to_h
puts capitalized_fruits_with_index.inspect

 

出力結果:

{0=>"Apple", 1=>"Banana", 2=>"Cherry"}

 

この例では、map.with_indexを使用して各要素を大文字に変換し、そのインデックスとともに新しいハッシュを生成しています。map.with_indexを使うことで、位置情報を保持しながら配列の各要素を加工する処理を容易に実現できます。

map後にnilを取り除く: compact

配列の変換処理の結果、nilが含まれる場合があります。そういった場合には、compactメソッドをチェーンさせることでnilを簡単に取り除くことができます。

numbers = [1, 2, nil, 4, 5]
non_nil_numbers = numbers.map { |n| n ? n * 2 : nil }.compact
p non_nil_numbers

 

実行結果:

 

[2, 4, 8, 10]

 

map後に多次元配列を一次元配列にする: flatten

mapの結果得られた配列がネストしている場合、flattenメソッドを使って平坦化(多次元配列を一次元配列に変換)することができます。

nested_arrays = [[1, 2], [3, 4], [5, 6]]
flattened_and_doubled = nested_arrays.map { |array| array.map { |n| n * 2 }}.flatten
p flattened_and_doubled

 

実行結果:

 

[2, 4, 6, 8, 10, 12]

 

mapメソッドを使ってみよう!

Rubyのmapメソッドを使用することで、配列やハッシュの各要素に対して一括で処理を実行し、その結果を新たな配列として得ることができます。この機能は、データの変換や加工を効率的に行いたい場合に非常に便利です。

例えば、次のコードでは、配列内の各数値を文字列に変換しています。

numbers = [1, 2, 3, 4, 5]
string_numbers = numbers.map { |number| number.to_s }
puts string_numbers
# 結果: ["1", "2", "3", "4", "5"]

このように、mapメソッドを使用すると、配列の各要素を効率的に操作することが可能です。複雑な処理も、ブロック内に記述することで簡単に表現できます。

実践練習:具体的に処理を見てみる

mapメソッドは、単にデータ型を変換するだけでなく、より具体的な処理を行うこともできます。たとえば、次のコードでは、配列の各要素に3を加えた新しい配列を作成しています。

numbers = [1, 2, 3, 4, 5]
added_numbers = numbers.map { |number| number + 3 }
puts added_numbers
# 結果: [4, 5, 6, 7, 8]

この例のように、mapメソッドを使えば、配列の各要素に対して一定の加算処理を行い、その結果を新しい配列として返すことができます。同様にして、他の算術演算や条件式を用いた複雑な操作も実現可能です。

実践練習:戻り値を使用する

mapメソッドの大きな特徴は、ブロックの最後に評価された式の結果が新しい配列の要素として追加されることです。この戻り値を活用することで、さまざまなデータ変換を効率的に行うことができます。

次の例では、配列の各要素が偶数であればそのまま、奇数であれば2を乗じた値を新しい配列として返しています。

numbers = [1, 2, 3, 4, 5]
processed_numbers = numbers.map do |number|
  if number.even?
    number
  else
    number * 2
  end
end
puts processed_numbers
# 結果: [2, 2, 6, 4, 10]

このようにmapメソッドを用いることで、条件分岐を含む複雑なロジックも、配列の各要素に適用し、新たな配列を得ることができます。これにより、コードの可読性と効率性を同時に向上させることが可能になります。

map!メソッドも使ってみよう!

map!メソッドを利用することで、配列の各要素に処理を適用し、その結果で元の配列自体を更新することができます。このメソッドは、mapメソッドと似ていますが、元の配列の内容を直接変更する点が異なります。

numbers = [1, 2, 3, 4, 5]
numbers.map! { |number| number ** 2 }
puts numbers
# 結果: [1, 4, 9, 16, 25]

この例では、配列numbersの各要素を二乗し、その結果で元の配列numbersを更新しています。これは、データの変換結果を追加の変数や配列に保存する必要がない場合に有用です。ただし、map!を使用する際には、元の配列が変更されることに注意しましょう。状況に応じて、元のデータを保持する必要がある場合はmapメソッドを使用する方が適切です。

mapをhashで利用する方法

Rubyのmapメソッドは、配列だけでなくハッシュに対しても使用することができます。ハッシュの場合、mapメソッドはキーと値のペアに対してブロック内の処理を適用し、結果を新しい配列として返します。

例えば、ハッシュの各値に特定の処理を適用したい場合、次のようにmapメソッドを使用することができます。

capitals = { japan: 'Tokyo', france: 'Paris', italy: 'Rome' }
uppercased_capitals = capitals.map { |key, value| [key, value.upcase] }.to_h
puts uppercased_capitals
# 結果: {:japan=>"TOKYO", :france=>"PARIS", :italy=>"ROME"}

この例では、ハッシュcapitalsの各値(都市名)を大文字に変換しています。ブロック内でキーと値のペアを[key, value.upcase]の形式で返し、最後にto_hメソッドを使用して配列の配列をハッシュに変換しています。

ハッシュの場合、mapメソッドはキーと値のペアに対して自由に処理を加えることができるため、データ加工の幅が広がります。これにより、柔軟なデータ処理が可能になります。

関連:【Ruby】 hashの使い方完全マニュアル | 追加, 更新, 削除, 高度な利用方法について現役エンジニアが解説します

【Ruby】 hashの使い方完全マニュアル | 追加, 更新, 削除, 高度な利用方法について現役エンジニアが解説します

類似メソッドとの違いについて

selectとの違い

selectメソッドは、特定の条件に合致する要素のみを抽出するために使用されます。これに対してmapメソッドは、配列やハッシュの全ての要素に対して処理を適用し、その結果からなる新しい配列を生成します。つまり、selectメソッドはフィルタリングに、mapメソッドは各要素の変換に利用されるという違いがあります。

関連:【Ruby】 selectメソッド完全マニュアル | 基礎から応用・filterとの違いについても解説

【Ruby】 selectメソッド完全マニュアル | 基礎から応用・filterとの違いについても解説

collectとの違い

前述のとおり、collectメソッドはmapメソッドと全く同じ機能を持ち、互換性があります。つまり、collectmapの間に機能的な違いはありません。どちらを使用するかは、個人の好みやプロジェクトのコーディング規約に依存します。

eachとの違い

eachメソッドも配列やハッシュの各要素に対して処理を実行しますが、eachは処理の結果を集めて新しい配列を返すことはしません。eachは各要素に対して指定したブロックの処理を実行するだけで、元の配列やハッシュを変更することなく、戻り値として元の配列やハッシュをそのまま返します。mapメソッドと異なり、eachを使っても新しい配列や変換されたデータを得ることはできません。

関連:【Ruby】eachメソッドの使い方の基礎から応用まで現役エンジニアが解説します

【Ruby】eachメソッドの使い方の基礎から応用まで現役エンジニアが解説します

他の配列操作メソッドについて

Rubyでは、mapselectのようなメソッド以外にも、配列を効率的に操作するための様々なメソッドが提供されています。例えば、reduce(またはinject)、filterall?any?none?findなど、配列やハッシュのデータを加工・調査するための多くのメソッドがあります。これらのメソッドを学ぶことで、より複雑なデータ処理や条件分岐、集計などを効率的に行うことができるようになります。

まとめ

本記事では、Rubyのmapメソッドの使い方、応用的な使い方、類似メソッドとの違いについて解説しました。配列やハッシュの各要素に対して処理を行い、その結果を新しい配列やハッシュとして返すmapメソッドは、Rubyプログラミングにおいて非常に便利なツールです。このメソッドを使いこなすことで、コードの記述を簡潔にし、プログラムの可読性と効率性を向上させることができます。また、selecteachといった他の配列操作メソッドと組み合わせることで、より柔軟なデータ処理を行うことが可能になります。ぜひこの機会に、mapメソッドを活用していろいろなコードを書いてみてください。