Dart3でdart:collectionに入った配列操作系のメンバーが便利
dartではList
やMap
などのIterable
なコレクションを操作するためのメソッド類が不足していました。それを補うため、Collection Packageがよく使われています。
2023年5月10日にリリースされたdart3でIterableにいくつかの便利なメソッドとプロパティが追加されたので紹介します。
nonNulls
null
な要素を除いたiterableを返します。
Collection PackageのwhereNotNullに相当します。collection packageではメソッドですが、こちらはプロパティです。
const list = [1, 2, null, 4, 5];
// List<int?>
final nonNullList = list.nonNulls.toList();
// List<int>
このメソッドの良いところは型から?が外れるところです。
firstOrNull, lastOrNull
Iterableの最初または最後の要素を取得します。もしリストが空の場合はnull
が返ります。
const emptyList = [];
list.firstOrNull;
// null
元からfirst
やlast
のプロパティがありますが、これは空の場合StateError
が発生します。
singleOrNull
Iterableの要素数がただ1つのとき、その要素を返します。要素数が空、または2つ以上の場合はnull
を返します。
const list = [1, 2, 3, 4, 5];
list.singleOrNull;
// null
元からsingle
のプロパティがありますが、これは要素数が1つでない場合StateError
が発生します。
elementAtOrNull
指定された位置の要素を取得します。負の数は指定できませんが、範囲外の要素を指定するとnull
を返します。
const list = [1, 2, 3, 4, 5];
list.elementAtOrNull(6);
// null
配列添え字やelementAt
で要素を取得する場合、範囲外の要素を取得しようとするとIndexError
になります。
indexed
リストをmapするときに同時にindexが欲しい場合があります。dart2までは標準ライブラリだけでやろうとするとasMap
を使って
const list = [1, 2, 3, 4, 5];
final mapped = list.asMap().entries.map((entry) {
final index = entry.key;
final value = entry.value;
return value * index;
},
);
// (0, 2, 6, 12, 20)
と書かなければなりませんでした。
新しく導入されたindexed
を使うと
list.indexed.map((element) {
var (index, value) = element;
return value * index;
});
書くことができます。indexed
は同じくdart3で導入されたRecordsが使われています。さらに同じく導入されたPatternsを使ってindex
を取り出すことができます。
またcollection forを使って
final mapped = [for (final (index, value) in list.indexed) value * index];
と書くこともできます。
どちらもあまりすっきりした書き方ではないと思うので、[Collection PackageのmapIndexed]を使って
import 'package:collection/collection.dart';
const list = [1, 2, 3, 4, 5];
print(list.mapIndexed((index, element) => element * index));
と書くのがおすすめです。dartのpackage:collectionを完全に理解する(ジェネリクスがわからない人向け)でさらに多くの便利メソッドを解説していますのでこちらもご覧ください。
Discussion