🍳

Dart3でdart:collectionに入った配列操作系のメンバーが便利

2023/06/15に公開

dartではListMapなどの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

元からfirstlastのプロパティがありますが、これは空の場合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