Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Add Iterable.elementAtOrNull extension #217

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 11 additions & 0 deletions lib/src/iterable_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,17 @@ extension IterableExtension<T> on Iterable<T> {
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;
natebosch marked this conversation as resolved.
Show resolved Hide resolved

/// 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]
Expand Down
11 changes: 11 additions & 0 deletions lib/src/list_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,17 @@ extension ListExtensions<E> on List<E> {
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;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious that there is no firstOrNull/lastOrNull defined on List.

/// Contiguous [slice]s of [this] with the given [length].
///
/// Each slice is a view of this list [length] elements long, except for the
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: collection
version: 1.16.1-dev
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK to go directly to 1.17.0 and publish.

version: 1.17.0-dev

description: Collections and utilities functions and classes related to collections.
repository: https://github.com/dart-lang/collection
Expand Down
29 changes: 29 additions & 0 deletions test/extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<RangeError>()));
});
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(<int>[]).slices(1), []);
Expand Down Expand Up @@ -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<RangeError>()));
});
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(<int>[].slices(1), []);
Expand Down