Rubyのflat_mapを完全攻略!mapとflattenの違いを初心者向けに徹底解説
生徒
「Rubyでデータを加工していたら、配列の中に配列が入った入れ子状態になってしまいました。これをバラして綺麗に一列にするにはどうすればいいですか?」
先生
「それは配列の平坦化ですね。Rubyにはmapとflattenを組み合わせる方法と、最初から一気に行うflat_mapという便利なメソッドがあります。」
生徒
「flat_mapを使うメリットは何ですか?」
先生
「動作がスマートで、コードが読みやすくなるんですよ。初心者の方でも分かりやすく使い分けを説明しますね!」
1. Rubyの配列と入れ子構造の基本
Ruby(ルビー)というプログラミング言語では、複数のデータをまとめて管理するために配列(はいれつ)という箱を使います。配列は、スーパーの買い物カゴのように、中にリンゴやバナナなどのデータを詰め込むことができます。
しかし、プログラムを組んでいると「カゴの中に、さらに小さなカゴが入っている」という状態になることがあります。これを入れ子(ネスト)構造と呼びます。例えば、クラスの名簿を作るときに、「1組の生徒の配列」と「2組の生徒の配列」をさらに一つの大きな箱にまとめた場合などがこれに当たります。この状態のままだと、全員の名前を一人ずつ取り出すときに少し不便です。そこで、中身を全部ぶちまけて一列に並べ直す作業が必要になります。これが今回のテーマである平坦化です。
2. mapメソッドでデータを加工する方法
平坦化の話の前に、まずは map(マップ)という非常に重要な命令について説明します。これは配列の中身一つ一つに対して「何か加工をしてね」とお願いする命令です。
パソコンを触ったことがない方向けに例えると、工場にあるベルトコンベアのようなものです。流れてくるミカン(データ)に対して、一つずつラベルを貼る(加工する)という作業を全自動で行ってくれます。加工が終わると、新しくラベルが貼られたミカンが詰まった新しいカゴを返してくれます。この map は、Rubyのプログラミングにおいて最も頻繁に使われる命令の一つです。
numbers = [1, 2, 3]
# 全ての数字を2倍にする加工
result = numbers.map do |n|
n * 2
end
p result
[2, 4, 6]
3. flattenメソッドで平坦化(バラバラ)にする
次に、入れ子になった配列を解消する flatten(フラットゥン)という命令を紹介します。英語の flatten は「平らにする」という意味です。その名の通り、二重、三重になっている配列の壁を取り払って、全ての要素を一列に並べ替えてくれます。
例えば、[[1, 2], [3, 4]] という配列があったとします。これは「1と2が入ったカゴ」と「3と4が入ったカゴ」が大きなカゴに入っている状態です。ここに flatten 命令を出すと、中のカゴを取り除いて [1, 2, 3, 4] というシンプルな一つのカゴにしてくれます。このように階層を壊して平らにすることを平坦化と言います。
4. mapとflattenを組み合わせた処理の例
実際の開発では、データを加工した結果として入れ子の配列が出来上がってしまうことがよくあります。例えば、ユーザーの名前を名字と名前に分割して、それを一つのリストにまとめたい場合などです。まずは map で加工し、その後に flatten で平らにするという二段構えの処理を見てみましょう。
names = ["田中 太郎", "佐藤 花子"]
# 1. 名字と名前に分ける(配列の中に配列ができる)
nested_names = names.map do |name|
name.split(" ")
end
# 2. 平らにする
final_names = nested_names.flatten
p final_names
["田中", "太郎", "佐藤", "花子"]
ここで split(スプリット)という言葉が出てきましたが、これは文字列を指定した場所(今回は空白)で切り分ける命令です。加工の結果、一度入れ子になってしまうのがポイントです。
5. flat_mapというスマートな解決策
ようやく本題の flat_map(フラットマップ)の登場です。先ほどの「加工して、そのあと平らにする」という二つの手順を、たった一度で行ってくれるのがこの命令です。名前も flat と map が合体していて分かりやすいですね。
なぜ flat_map を使うのでしょうか。それは、一度無駄な「入れ子の配列」を作らなくて済むからです。コンピューターにとっても、人間がコードを読むときにとっても、手順が少ないほうが間違いが少なく、スッキリと理解できます。プログラミング未経験の方は、この「二つの作業を一つにまとめる」という考え方が、効率的なプログラムを書くコツだと覚えておいてください。
fruits = ["apple", "orange"]
# 加工と平坦化を同時に行う
result = fruits.flat_map do |fruit|
[fruit, fruit.upcase]
end
p result
["apple", "APPLE", "orange", "ORANGE"]
この例では、小文字の果物名から「小文字と大文字のセット」を作り、それを一列に並べています。upcase はアルファベットを大文字にする命令です。
6. flat_mapとmap.flattenの動作の違い
見た目は似ていますが、実は細かい動きに違いがあります。一番の大きな違いは「どこまで平らにするか」という深さです。flatten は、何も指定しないと三重、四重になっている深い入れ子も全て一気に一列にします。しかし、flat_map が平らにしてくれるのは一段階だけです。
もし、データの中にさらに深い配列が隠れていて、それを維持したい場合には flat_map のほうが安全です。逆に、どんなに深くても全てバラバラにしたいなら map の後に flatten を使うのが適切です。このように、自分のやりたいことに合わせて道具を使い分けるのがRubyエンジニアの腕の見せ所です。専門用語では、この一階層だけ平らにすることを「浅い平坦化」と呼んだりします。
7. flat_mapの便利な応用:データのフィルタリング
flat_map の面白い使い道として、特定の条件のデータだけを除去したり増やしたりする技があります。加工の結果として空の配列 [] を返すと、平坦化されるときにその要素は消えてしまいます。逆に二つ以上の要素を入れた配列を返せば、要素が増えます。
これは map だけではできない芸当です。map は必ず元の要素数と同じだけの結果を返しますが、flat_map は結果の数を自由に変えられる魔法のようなベルトコンベアなのです。条件に合うものだけを取り出す select メソッドのような動きも、加工と同時に行えるため非常に強力です。
numbers = [1, 2, 3, 4, 5]
# 偶数なら2倍にして2個入れ、奇数なら何も入れない
result = numbers.flat_map do |n|
if n.even?
[n * 2, n * 2]
else
[]
end
end
p result
[4, 4, 8, 8]
8. Enumerableというグループの秘密
ここまで紹介した map や flat_map は、RubyのEnumerable(エニュメラブル)というグループに属しています。日本語では「列挙可能」という意味ですが、簡単に言えば「順番に並んだデータを扱うのが得意な仲間たち」のことです。
Rubyには配列以外にも、ハッシュ(辞書のようなデータ)など色々なデータの集まりがありますが、Enumerableの仲間であれば、同じように map や flat_map を使うことができます。一つ一つの命令を別々に覚えるのではなく、「集まりを扱う仲間たちの共通ルール」だと理解すると、学習がぐっと楽になります。パソコンの操作で、どのソフトでも「保存」は同じメニューにあるのと似ていますね。
9. 初心者が間違いやすいポイント:戻り値の意識
プログラミングを始めたばかりの方がよくやってしまう失敗は、flat_map の中で配列ではないものを返してしまうことです。flat_map は「中身が配列であることを期待して、それを平らにする」命令です。もし配列を返さない場合、ただの map と同じ動きになってしまい、せっかくの平坦化機能が働きません。
また、ピリオド . で命令をつなげる順番にも注意しましょう。names.flatten.map と書いてしまうと、平らにしてから加工することになり、やりたいことと逆になってしまう場合があります。Rubyは左から右へと順番に命令が実行されるので、データの流れを意識して記述することが大切です。これをメソッドチェーンと呼びます。
10. 保守性の高いコードを書くために
最後に、なぜ flat_map のような専門的な命令を覚える必要があるのかをお話しします。それは、後からプログラムを読む自分や仲間のためです。プログラミングの世界では、一度書いたコードは何度も読み返されます。そのとき、map と flatten がバラバラに書いてあるよりも、flat_map と書いてあるほうが「あ、ここでは加工と平坦化をセットでやってるんだな」と一瞬で意図が伝わります。
読みやすいコードは、不具合(バグ)を見つけやすく、修正もしやすいです。プログラミングはコンピューターへの命令であると同時に、人間同士のコミュニケーションでもあります。今回学んだテクニックを使って、ぜひ綺麗でスマートなRubyプログラムを書いてみてください。一歩ずつ、楽しみながら学んでいきましょう!