Add `count` and `countWhere` extensions. (#196)
* Add `count` and `countWhere` extensions.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e5a4af..d4263e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
## 1.16.0
* Use a stable sort algorithm in the `IterableExtension.sortedBy` method.
+* Add `count` and `countWhere` extensions on `Iterable`.
## 1.15.0
diff --git a/lib/src/empty_unmodifiable_set.dart b/lib/src/empty_unmodifiable_set.dart
index 882b6c8..725dfc0 100644
--- a/lib/src/empty_unmodifiable_set.dart
+++ b/lib/src/empty_unmodifiable_set.dart
@@ -4,7 +4,8 @@
import 'dart:collection';
-import 'package:collection/collection.dart';
+import 'unmodifiable_wrappers.dart';
+import 'wrappers.dart';
/// An unmodifiable, empty set which can be constant.
class EmptyUnmodifiableSet<E> extends IterableBase<E>
diff --git a/lib/src/iterable_extensions.dart b/lib/src/iterable_extensions.dart
index b0bf0ad..1c82bc4 100644
--- a/lib/src/iterable_extensions.dart
+++ b/lib/src/iterable_extensions.dart
@@ -18,6 +18,46 @@
/// iterables with specific element types include those of
/// [IterableComparableExtension] and [IterableNullableExtension].
extension IterableExtension<T> on Iterable<T> {
+ /// Counts the elements that are equal to [value].
+ ///
+ /// Returns the number of elements of this iterable
+ /// which are equal to [value] according to their `==`
+ /// operation.
+ ///
+ /// Example:
+ /// ```dart
+ /// var nullCount = maybeValues.count(null);
+ /// ```
+ ///
+ /// Equivalent to `.countWhere((e) => e == value)`.
+ int count(T value) {
+ var result = 0;
+ for (var element in this) {
+ if (element == value) result++;
+ }
+ return result;
+ }
+
+ /// Counts the elements that satisfy [test].
+ ///
+ /// Returns the number of elements of this iterable
+ /// which [test] returns `true` for.
+ /// The test must not modify this iterable.
+ ///
+ /// Example:
+ /// ```dart
+ /// var primeCount = integers.countWhere(isPrime);
+ /// ```
+ ///
+ /// Equivalent to `.where(test).length`.
+ int countWhere(bool Function(T element) test) {
+ var result = 0;
+ for (var element in this) {
+ if (test(element)) result++;
+ }
+ return result;
+ }
+
/// Selects [count] elements at random from this iterable.
///
/// The returned list contains [count] different elements of the iterable.
diff --git a/test/extensions_test.dart b/test/extensions_test.dart
index 0ea2d95..b32a0d4 100644
--- a/test/extensions_test.dart
+++ b/test/extensions_test.dart
@@ -10,6 +10,58 @@
void main() {
group('Iterable', () {
group('of any', () {
+ group('.count', () {
+ test('empty', () {
+ // Empty iterable.
+ var iterable = [1, 2, 3, 2, 3, 2].where((_) => false);
+ expect(iterable.count(1), 0);
+ expect(<int>[].count(1), 0);
+ });
+ test('none', () {
+ var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+ expect(iterable.count(0), 0);
+ expect(<int>[4].count(0), 0);
+ });
+ test('single', () {
+ var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+ expect(iterable.count(4), 1);
+ expect(<int>[4].count(4), 1);
+ });
+ test('multiple', () {
+ var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+ expect(iterable.count(2), 3);
+ expect(iterable.count(3), 2);
+ expect(<int>[2, 3, 2].count(2), 2);
+ });
+ test('uses element equality', () {
+ var iterable = <Object>[EqTo(2), 2];
+ expect(iterable.count(2), 2);
+ });
+ });
+ group('.countWhere', () {
+ test('empty', () {
+ // Empty iterable.
+ var iterable = [1, 2, 3, 2, 3, 2].where((_) => false);
+ expect(iterable.countWhere((_) => true), 0);
+ expect(<int>[].countWhere((_) => true), 0);
+ });
+ test('none', () {
+ var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+ expect(iterable.countWhere((_) => false), 0);
+ expect(<int>[4].countWhere((_) => false), 0);
+ });
+ test('single', () {
+ var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+ expect(iterable.countWhere((x) => x == 4), 1);
+ expect(<int>[4].countWhere((x) => x == 4), 1);
+ });
+ test('multiple', () {
+ var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+ expect(iterable.countWhere((x) => x == 2), 3);
+ expect(iterable.countWhere((x) => x == 3), 2);
+ expect(<int>[2, 3, 2].countWhere((x) => x == 2), 2);
+ });
+ });
group('.whereNot', () {
test('empty', () {
expect(iterable([]).whereNot(unreachable), isEmpty);
@@ -1703,3 +1755,14 @@
/// Tests an integer for being odd.
bool isOdd(int x) => x.isOdd;
+
+/// Objects which claim to be equal to other values.
+class EqTo {
+ final Object? value;
+ EqTo(this.value);
+ @override
+ int get hashCode => value.hashCode;
+ @override
+ bool operator ==(Object other) =>
+ value == (other is EqTo ? other.value : other);
+}