From 8c2f43071a66dfb487c4404170a69d3775aa2107 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Wed, 6 Sep 2023 10:33:24 -0700 Subject: [PATCH] Add ListExtensions.firstOrNull, lastOrNull, singleOrNull. --- CHANGELOG.md | 2 ++ lib/src/list_extensions.dart | 19 +++++++++++++++++++ test/extensions_test.dart | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c27f014..fd2c268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Adds `shuffled` to `IterableExtension`. - Shuffle `IterableExtension.sample` results. +* Add `List.firstOrNull`, `List.lastOrNull`, and `List.singleOrNull` extension methods. + They repeat corresponding methods for `Iterable`, but avoid creating iterator objects. ## 1.18.0 diff --git a/lib/src/list_extensions.dart b/lib/src/list_extensions.dart index 40fa8af..12ff628 100644 --- a/lib/src/list_extensions.dart +++ b/lib/src/list_extensions.dart @@ -286,6 +286,25 @@ extension ListExtensions on List { yield slice(i, min(i + length, this.length)); } } + + /// The first element, or `null` if the list is empty. + E? get firstOrNull { + return isNotEmpty ? this[0] : null; + } + + /// The last element, or `null` if the list is empty. + E? get lastOrNull { + final length = this.length; + return length != 0 ? this[length - 1] : null; + } + + /// The single element of the list, or `null`. + /// + /// The value is `null` if the list is empty + /// or it contains more than one element. + E? get singleOrNull { + return length == 1 ? this[0] : null; + } } /// Various extensions on lists of comparable elements. diff --git a/test/extensions_test.dart b/test/extensions_test.dart index 229d6e2..ad865c5 100644 --- a/test/extensions_test.dart +++ b/test/extensions_test.dart @@ -1864,6 +1864,39 @@ void main() { expect(() => [1].slices(0), throwsRangeError); }); }); + group('.firstOrNull', () { + test('empty', () { + expect([].firstOrNull, null); + }); + test('single', () { + expect([1].firstOrNull, 1); + }); + test('first of multiple', () { + expect([1, 3, 5].firstOrNull, 1); + }); + }); + group('.lastOrNull', () { + test('empty', () { + expect([].lastOrNull, null); + }); + test('single', () { + expect([1].lastOrNull, 1); + }); + test('last of multiple', () { + expect([1, 3, 5].lastOrNull, 5); + }); + }); + group('.singleOrNull', () { + test('empty', () { + expect([].singleOrNull, null); + }); + test('single', () { + expect([1].singleOrNull, 1); + }); + test('multiple', () { + expect([1, 3, 5].singleOrNull, null); + }); + }); }); group('on comparable', () { group('.binarySearch', () {