From 414ffa1bc8ba18bd608bbf916d95715311d89ac1 Mon Sep 17 00:00:00 2001 From: Yuxiang Liu Date: Fri, 3 Jun 2022 23:19:45 +0800 Subject: [PATCH] Add elementAtOrNull extensions (#217) Add extensions on List and Iterable to read an element without risk of exceptions. --- CHANGELOG.md | 4 +++- lib/src/iterable_extensions.dart | 11 +++++++++++ lib/src/list_extensions.dart | 11 +++++++++++ pubspec.yaml | 2 +- test/extensions_test.dart | 29 +++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f36e987..ea92e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -## 1.16.1-dev +## 1.17.0-dev + +* Add `Iterable.elementAtOrNull` and `List.elementAtOrNull` extension methods. * Add a top-level `lastBy()` function that converts an `Iterable` to a `Map` by grouping its elements using a function, keeping the last element for each diff --git a/lib/src/iterable_extensions.dart b/lib/src/iterable_extensions.dart index 88f320d..3af5124 100644 --- a/lib/src/iterable_extensions.dart +++ b/lib/src/iterable_extensions.dart @@ -354,6 +354,17 @@ extension IterableExtension on Iterable { return null; } + /// The [index]th element, or `null` if there is no such element. + /// + /// Returns the element at position [index] of this iterable, + /// just like [elementAt], if this iterable has such an element. + /// If this iterable does not have enough elements to have one with the given + /// [index], the `null` value is returned, unlike [elementAt] which throws + /// instead. + /// + /// The [index] must not be negative. + T? elementAtOrNull(int index) => skip(index).firstOrNull; + /// Associates the elements in [this] by the value returned by [key]. /// /// Returns a map from keys computed by [key] to the last value for which [key] diff --git a/lib/src/list_extensions.dart b/lib/src/list_extensions.dart index 4d6ae3f..4bb719a 100644 --- a/lib/src/list_extensions.dart +++ b/lib/src/list_extensions.dart @@ -259,6 +259,17 @@ extension ListExtensions on List { return true; } + /// The [index]th element, or `null` if there is no such element. + /// + /// Returns the element at position [index] of this list, + /// just like [elementAt], if this list has such an element. + /// If this list does not have enough elements to have one with the given + /// [index], the `null` value is returned, unlike [elementAt] which throws + /// instead. + /// + /// The [index] must not be negative. + E? elementAtOrNull(int index) => (index < length) ? this[index] : null; + /// Contiguous [slice]s of [this] with the given [length]. /// /// Each slice is a view of this list [length] elements long, except for the diff --git a/pubspec.yaml b/pubspec.yaml index 436a1e1..07a5fa1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: collection -version: 1.16.1-dev +version: 1.17.0-dev description: Collections and utilities functions and classes related to collections. repository: https://github.com/dart-lang/collection diff --git a/test/extensions_test.dart b/test/extensions_test.dart index ce4b2e9..31bb458 100644 --- a/test/extensions_test.dart +++ b/test/extensions_test.dart @@ -1160,6 +1160,21 @@ void main() { } }); }); + group('.elementAtOrNull', () { + test('empty', () async { + expect(iterable([]).elementAtOrNull(0), isNull); + }); + test('negative index', () async { + expect(() => iterable([1]).elementAtOrNull(-1), + throwsA(isA())); + }); + test('index within range', () async { + expect(iterable([1]).elementAtOrNull(0), 1); + }); + test('index too high', () async { + expect(iterable([1]).elementAtOrNull(1), isNull); + }); + }); group('.slices', () { test('empty', () { expect(iterable([]).slices(1), []); @@ -1748,6 +1763,20 @@ void main() { ['1', 'b']); }); }); + group('.elementAtOrNull', () { + test('empty', () async { + expect([].elementAtOrNull(0), isNull); + }); + test('negative index', () async { + expect(() => [1].elementAtOrNull(-1), throwsA(isA())); + }); + test('index within range', () async { + expect([1].elementAtOrNull(0), 1); + }); + test('index too high', () async { + expect([1].elementAtOrNull(1), isNull); + }); + }); group('.slices', () { test('empty', () { expect([].slices(1), []);