#21 Dartで学ぶコレクション操作の応用の基本
はじめに
Dartでリスト(複数の値をまとめて扱う入れ物、List)を扱っていると、「条件に合う要素だけ取り出したい」「全要素を別の形に変換したい」「全要素を集計して1つの値にまとめたい」という場面によく出会います。こうした処理はfor文でも書けます。しかしDartにはwhere・map・fold(またはreduce)という専用のメソッドが用意されており、これらを使ったコレクション操作の応用テクニックを覚えると便利です。他言語の「フィルタ」「マップ」「集約」に相当し、使いこなすと処理の意図が一目で分かる短いコードになります。Flutter(Dartのアプリ開発フレームワーク)でも頻出なので押さえておきましょう。
where:条件に合う要素だけを絞り込む
whereは、リストの中から「条件を満たす要素だけ」を取り出すメソッドです。条件を判定する処理(ラムダ式と呼ばれる、その場で書ける小さな関数)を引数として渡します。
final numbers = [1, 2, 3, 4, 5, 6];
final evens = numbers.where((n) => n % 2 == 0).toList();
// evens は [2, 4, 6]
(n) => n % 2 == 0は「2で割った余りが0(=偶数)」という条件を表すラムダ式です。注意したいのが、whereの戻り値はListではなくIterable(反復可能な要素の集まり)という型になる点です。リストとして使うには.toList()で変換する必要があり、これを忘れて直接List型に代入すると型エラーになるので注意しましょう。
map:全要素を別の形に変換する
mapは、リストの全要素に同じ処理を適用し、変換後の値をまとめて返すメソッドです。
final names = ['taro', 'hanako', 'jiro'];
final upperNames = names.map((n) => n.toUpperCase()).toList();
// upperNames は [TARO, HANAKO, JIRO]
toUpperCase()(文字列を大文字に変換するメソッド)を各要素に適用しています。mapもwhereと同じく戻り値はIterableなので、リストとして使うには.toList()が必要です。要素数を変えずに中身だけ変換したい場合に使う、という点がwhereとの違いです。
fold・reduce:全要素を1つの値にまとめる
foldは、リストの全要素を順番に処理しながら1つの値に集約(合計・連結など)するメソッドです。初期値と、要素を1つずつ足し込んでいく処理を指定します。
final numbers = [1, 2, 3, 4, 5];
final total = numbers.fold(0, (sum, n) => sum + n);
// total は 15
最初の引数0が初期値、sumが計算結果、nが今処理している要素です。似たreduceは初期値を指定せず最初の要素を初期値にするため、空リストで呼ぶとエラーになります。foldは初期値を自分で渡すため空リストでも安全なので、迷ったらfoldを使いましょう。
3つを組み合わせる
これらはメソッドチェーン(メソッドを連続して呼び出す書き方)としてつなげて書くことができます。
final scores = [55, 80, 42, 90, 65];
final passedTotal = scores
.where((s) => s >= 60)
.map((s) => s * 1.1)
.fold(0.0, (sum, s) => sum + s);
「60点以上を絞り込み→1.1倍のボーナス点に変換→合計する」処理が、for文なしで1つの流れとして書けます。最後にfoldやreduceを呼べば.toList()なしで完結できるのがIterableを活かしたDartらしい書き方です。ただしチェーンが長いと読みにくくなるので、複雑な処理は変数に分けましょう。
他言語との違い・つまずきやすい点
Swiftのfilter・map・reduceやJavaScriptのfilter・mapと役割はほぼ同じです。ただしDartはwhereとmapの戻り値が即座にListにならずIterableになる点が最大の違いです。これは不要な中間リストを作らず必要な時点でまとめて計算する「遅延評価」が働くためです。変換結果を使い回すなら.toList()で確定させないと、参照のたびに計算がやり直される点に注意しましょう。
まとめ
whereは絞り込み、mapは変換、foldは集約、とそれぞれ役割がはっきりしています。Dart特有のIterableと.toList()の関係さえ理解してしまえば、Flutterアプリのリスト表示など様々な場面で自然に使えるようになります。まずはfor文で書いてから「これはwhereやmapで書けないか」と置き換える練習をしてみてください。
関連記事
本ページはプロモーションを含みます。
参考書籍(PR)
Dartをもっと学びたい方には「ゼロから学ぶFlutterアプリ開発」がおすすめです。
PR
コードを書かずに自動化したい方へ
「学んだけど自分の作業に組み込む時間がない」という方向けに、ダブルクリックで動く Windows専用の自動化ツールをオーダーメイドで作成しています。気になる方は こちらをご覧ください。
コメント
コメントを投稿