_Ziens_

Dart distinctBy - filter unique elements (optionally replaces duplicates with a new value)

Sep 20th, 2020 (edited)
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 2.67 KB | None | 0 0
  1. extension IteratorExt<T> on Iterable<T> {
  2.   /// Returns [Iterable] that passes only unique elements.
  3.   /// Elements is comparing by [keySelector].
  4.   /// When some element repeats than [onDuplicate] calls to either ignore it
  5.   /// (if [onDuplicate] is not provided or if it returns `null`)
  6.   /// or replace with a new value.
  7.   /// If element returning by [onDuplicate] is equals to original element or has
  8.   /// a key that already exists it will be ignored.
  9.    Iterable<T> distinctBy(Object Function(T) keySelector,
  10.           {T Function(T old, T current) onDuplicate}) =>
  11.       _DistinctIterable(this, keySelector, onDuplicate);
  12. }
  13.  
  14. class _DistinctIterable<T> extends Iterable<T> {
  15.   final Iterable<T> _iterable;
  16.   final Object Function(T) _keySelector;
  17.   final T Function(T old, T current) _onDuplicate;
  18.   final Map<Object, T> uniqueElements = {};
  19.  
  20.   _DistinctIterable(
  21.     this._iterable,
  22.     this._keySelector,
  23.     T Function(T, T) onDuplicate,
  24.   ) : _onDuplicate = onDuplicate ?? ((old, curr) => null);
  25.  
  26.   Iterator<T> get iterator {
  27.     _iterable.forEach((element) {
  28.       final key = _keySelector(element);
  29.  
  30.       final old = uniqueElements[key];
  31.       if (old != null) {
  32.         final value = _onDuplicate(old, element);
  33.         if (value != null) uniqueElements[_keySelector(value)] = value;
  34.       } else
  35.         uniqueElements[key] = element;
  36.     });
  37.  
  38.     return uniqueElements.values.iterator;
  39.   }
  40. }
  41.  
  42. void main() {
  43.   // 1, 3, 5
  44.   print([1, 3, 5, 1, 5].distinctBy((i) => i).join(", "));
  45.  
  46.   // 1, 3, 5, 2, 10
  47.   print(
  48.       [1, 3, 5, 1, 5].distinctBy((i) => i, onDuplicate: (old, current ) => old + current).join(", "));
  49.  
  50.   final collection = [
  51.     KeyValuePair("A", 1),
  52.     KeyValuePair("B", 3),
  53.     KeyValuePair("C", 5),
  54.     KeyValuePair("D", 1),
  55.     KeyValuePair("E", 5),
  56.   ];
  57.  
  58.   // [A, 1], [B, 3], [C, 5]
  59.   print(collection.distinctBy((obj) => obj.value).join(", "));
  60.  
  61.   // [A, 1], [B, 3], [C, 5], [D (duplicated from A), 2], [E (duplicated from C), 10]
  62.   print(collection
  63.       .distinctBy((obj) => obj.value,
  64.       onDuplicate: (old, current) => KeyValuePair(
  65.         "${current.key} (duplicated from ${old.key})",
  66.         old.value + current.value,
  67.       ))
  68.       .join(", "));
  69. }
  70.  
  71. class KeyValuePair {
  72.   final String key;
  73.   final int value;
  74.  
  75.   const KeyValuePair(this.key, this.value);
  76.  
  77.   @override
  78.   String toString() => "[$key, $value]";
  79.  
  80.   @override
  81.   bool operator ==(Object other) =>
  82.       identical(this, other) ||
  83.       other is KeyValuePair &&
  84.           runtimeType == other.runtimeType &&
  85.           key == other.key &&
  86.           value == other.value;
  87.  
  88.   @override
  89.   int get hashCode => key.hashCode ^ value.hashCode;
  90. }
Add Comment
Please, Sign In to add comment