Skip to content

Commit

Permalink
Move subtract to IterableExtension
Browse files Browse the repository at this point in the history
As it solely acts on iterable and doesn't need lists.
  • Loading branch information
ebraminio committed Aug 16, 2023
1 parent 2ace49d commit 72431c0
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 41 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## 1.19.0-wip

- Adds `subtract` to `ListExtensions`.
- Adds `subtract` to `IterableExtension`.
- Adds `shuffled` to `IterableExtension`.
- Shuffle `IterableExtension.sample` results.

Expand Down
23 changes: 23 additions & 0 deletions lib/src/iterable_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,29 @@ extension IterableExtension<T> on Iterable<T> {
yield slice;
}
}

/// Returns an iterable of the elements in this iterable that are not present
/// in [other].
///
/// It's aware about occurrence count and removes things only the amount
/// they are present in [other] but it's indifferent about but the order of
/// items in [other].
///
/// It assumes the iterable items have consistent `==` and `hashCode`.
Iterable<T> subtract(Iterable<T> other) sync* {
var elementsCount =
other.groupFoldBy<T, int>(identity, (count, _) => (count ?? 0) + 1);
for (var element in this) {
var count = elementsCount[element];
if (count == null) {
yield element;
} else if (count == 1) {
elementsCount.remove(element);
} else {
elementsCount[element] = count - 1;
}
}
}
}

/// Extensions that apply to iterables with a nullable element type.
Expand Down
23 changes: 0 additions & 23 deletions lib/src/list_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'dart:math';
import 'algorithms.dart';
import 'algorithms.dart' as algorithms;
import 'equality.dart';
import 'iterable_extensions.dart';
import 'utils.dart';

/// Various extensions on lists of arbitrary elements.
Expand Down Expand Up @@ -287,28 +286,6 @@ extension ListExtensions<E> on List<E> {
yield slice(i, min(i + length, this.length));
}
}

/// Returns an iterable of the elements in this list that are not present in
/// [other].
///
/// It's aware about occurrence count and removes things only the amount
/// they are present in [other].
///
/// It assumes the list items have consistent `==` and `hashCode`.
Iterable<E> subtract(List<E> other) sync* {
var elementsCount =
other.groupFoldBy<E, int>(identity, (count, _) => (count ?? 0) + 1);
for (var element in this) {
var count = elementsCount[element];
if (count == null) {
yield element;
} else if (count == 1) {
elementsCount.remove(element);
} else {
elementsCount[element] = count - 1;
}
}
}
}

/// Various extensions on lists of comparable elements.
Expand Down
34 changes: 17 additions & 17 deletions test/extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,23 @@ void main() {
expect(l3.toList(), [4, 5]);
});
});
group('.subtract', () {
test('empty', () {
expect(iterable(<int>[]).subtract([]), []);
});
test('returns the same list when it shares nothing with the other', () {
expect(iterable([1, 2, 3, 4]).subtract([5]), [1, 2, 3, 4]);
});
test('removes two element', () {
expect(iterable([1, 2, 3, 4]).subtract([2, 3]), [1, 4]);
});
test('removes only one of the occurrence', () {
expect(iterable([1, 2, 2, 3]).subtract([2]), [1, 2, 3]);
});
test('removes only two of the occurrences', () {
expect(iterable([1, 2, 2, 3]).subtract([2, 0, 2]), [1, 3]);
});
});
});

group('Comparator', () {
Expand Down Expand Up @@ -1953,23 +1970,6 @@ void main() {
expect(list, [9, 8, 5, 6, 3, 2, 4, 7, 1]);
});
});
group('.subtract', () {
test('empty', () {
expect(<int>[].subtract([]), []);
});
test('returns the same list when it shares nothing with the other', () {
expect([1, 2, 3, 4].subtract([5]), [1, 2, 3, 4]);
});
test('removes two element', () {
expect([1, 2, 3, 4].subtract([2, 3]), [1, 4]);
});
test('removes only one of the occurrence', () {
expect([1, 2, 2, 3].subtract([2]), [1, 2, 3]);
});
test('removes only two of the occurrences', () {
expect([1, 2, 2, 3].subtract([2, 0, 2]), [1, 3]);
});
});
});
}

Expand Down

0 comments on commit 72431c0

Please sign in to comment.