#21 Scalaで学ぶコレクション操作の応用の基本

はじめに

プログラミングをしていると、「リストの中から条件に合うものだけ取り出したい」「リストの中身をすべて別の形に変換したい」という場面によく出会います。Scalaでは、こうした処理をforループで何行も書く必要はありません。コレクション(複数の値をまとめて扱うためのデータの入れ物。リストや配列などの総称)に用意されたメソッド一つで、簡潔に書けます。今回は、その代表格であるfilter(フィルタ)とmap(マップ)、そして少し発展的なreduceを中心に、Scalaらしいコレクション操作の考え方を紹介します。

filterで条件に合う要素だけを取り出す

filterは、コレクションの中から「条件を満たす要素だけ」を残して新しいコレクションを作るメソッドです。例えば整数のリストから偶数だけを取り出したいときは、次のように書けます。

val numbers = List(1, 2, 3, 4, 5, 6)
val evens = numbers.filter(n => n % 2 == 0)
// evens: List(2, 4, 6)

n => n % 2 == 0の部分は「無名関数(名前を付けずにその場で定義する関数)」です。「引数nを受け取り、nが2で割り切れるかどうかを判定して返す」という処理を、その場で書いています。他の言語のfor文で「if文で条件を判定し、合致したら新しいリストにappendする」という処理を、Scalaでは1行で表現できるのがポイントです。

mapで要素をすべて変換する

mapは、コレクションの各要素に同じ処理を適用し、その結果を新しいコレクションとして返すメソッドです。例えば、すべての数値を2倍にしたい場合は次のように書きます。

val numbers = List(1, 2, 3)
val doubled = numbers.map(n => n * 2)
// doubled: List(2, 4, 6)

filterが「要素を選ぶ」処理であるのに対し、mapは「要素を作り変える」処理だと覚えておくと区別しやすいです。Pythonのリスト内包表記([x*2 for x in numbers])や、Javaのストリームでの.map()に近い考え方です。ただしScalaでは、mapもfilterも「コレクションそのものが最初から備えているメソッド」である点が特徴です。メソッドチェーン(メソッドを.で連続してつなげる書き方)で、filterとmapを組み合わせることもよくあります。

val result = numbers.filter(n => n % 2 == 0).map(n => n * 10)
// result: List(20, 40, 60)

省略記法にも慣れておこう

Scalaでは、無名関数の書き方をさらに短くできます。n => n % 2 == 0は_ % 2 == 0とも書け、アンダースコア_が「その位置の引数」を表します。慣れないうちは読みにくく感じますが、実務コードで頻出するため、見かけたら覚えておくとよいでしょう。

reduceで集約する

複数の要素を1つの値にまとめたいときはreduceを使います。例えばリストの合計を求める場合は次のようになります。

val numbers = List(1, 2, 3, 4)
val total = numbers.reduce((a, b) => a + b)
// total: 10

これは「隣り合う要素を順番に足し合わせる」処理です。合計だけならnumbers.sumもありますが、「最大値を求める」「文字列を連結する」など独自の集約ルールを作りたいときにreduceが役立ちます。

つまずきやすいポイント

filterやmapは、元のコレクションを直接書き換えるのではなく、新しいコレクションを作って返す点に注意してください。Scalaのリストはデフォルトで「イミュータブル(不変。一度作った後は中身を変更できない性質)」です。そのため、numbers.filter(...)を呼んでもnumbers自体は変化しません。結果を使いたい場合は、必ず戻り値を新しい変数に代入する必要があります。この「元のデータは変えず、新しいデータを作って返す」という考え方は、バグの少ないコードを書くうえで重要な発想なので、最初のうちから意識しておくとよいでしょう。

まとめ

今回はScalaのコレクション操作の中でも基本となる、filter・map・reduceの使い方を紹介しました。条件で絞り込むfilter、要素を変換するmap、集約するreduceを組み合わせることで、for文を何行も書かずに、意図の伝わりやすい簡潔なコードが書けるようになります。最初は無名関数の書き方に戸惑うかもしれませんが、少しずつ慣れていけば、他の言語のリスト内包表記やストリームAPIとの共通点も見えてくるはずです。ぜひ手元のコードで試してみてください。

関連記事


本ページはプロモーションを含みます。

参考書籍(PR)

Scalaをもっと学びたい方には「実践Scala入門」がおすすめです。


PR

コードを書かずに自動化したい方へ

「学んだけど自分の作業に組み込む時間がない」という方向けに、ダブルクリックで動くWindows専用の自動化ツールをオーダーメイドで作成しています。気になる方はこちらをご覧ください。

コメント

このブログの人気の投稿

#25 Rustで学ぶAI API(ChatGPT等)の呼び出し方の基本

#8 C++で学ぶ文字列操作の基本

#16 TypeScriptで学ぶ辞書型(マップ)の基本