import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:nc_photos/override_comparator.dart'; import 'package:tuple/tuple.dart'; extension IterableExtension on Iterable { /// Return a new sorted list List sorted([int Function(T a, T b)? compare]) => toList()..sort(compare); /// Return a new stable sorted list List stableSorted([int Function(T a, T b)? compare]) => toList()..stableSort(compare); /// Return a string representation of this iterable by joining the result of /// toString for each items String toReadableString() => "[${join(', ')}]"; Iterable mapWithIndex(U Function(int index, T element) fn) sync* { int i = 0; for (final e in this) { yield fn(i++, e); } } /// The current elements of this iterable modified by async function [fn]. /// /// The result of [fn] will be emitted by the returned stream in the same /// order as this iterable. /// /// If [simultaneousFuture] > 1, [fn] will be called multiple times before /// awaiting their results. Stream mapStream( Future Function(T element) fn, [ simultaneousFuture = 1, ]) async* { final container = >[]; for (final e in this) { container.add(fn(e)); if (container.length >= simultaneousFuture) { for (final result in await Future.wait(container)) { yield result; } container.clear(); } } if (container.isNotEmpty) { for (final result in await Future.wait(container)) { yield result; } } } /// Invokes async function [fn] on each element of this iterable in iteration /// order. /// /// If [simultaneousFuture] > 1, [fn] will be called multiple times before /// awaiting their results. Future forEachAsync( Future Function(T element) fn, [ simultaneousFuture = 1, ]) async { final container = []; for (final e in this) { container.add(fn(e)); if (container.length >= simultaneousFuture) { await Future.wait(container); container.clear(); } } if (container.isNotEmpty) { await Future.wait(container); } } Iterable> withIndex() => mapWithIndex((i, e) => Tuple2(i, e)); /// Whether the collection contains an element equal to [element] using the /// equality function [equalFn] bool containsIf(T element, bool Function(T a, T b) equalFn) => any((e) => equalFn(e, element)); /// Same as [contains] but uses [identical] to compare the objects bool containsIdentical(T element) => containsIf(element, (a, b) => identical(a, b)); Iterable>> groupBy({required U Function(T e) key}) { final map = fold>>( {}, (previousValue, element) => previousValue..putIfAbsent(key(element), () => []).add(element)); return map.entries.map((e) => Tuple2(e.key, e.value)); } /// Return a new list with only distinct elements List distinct() { final s = {}; return where((element) => s.add(element)).toList(); } /// Return a new list with only distinct elements determined by [equalFn] List distinctIf( bool Function(T a, T b) equalFn, int Function(T a) hashCodeFn) { final s = >{}; return where((element) => s.add(OverrideComparator(element, equalFn, hashCodeFn))).toList(); } /// Invokes [action] on each element of this iterable in iteration order /// lazily Iterable forEachLazy(void Function(T element) action) sync* { for (final e in this) { action(e); yield e; } } Future> computeAll(ComputeCallback callback) async { return await compute( _computeAllImpl, _ComputeAllMessage(callback, asList())); } /// Return a list containing elements in this iterable /// /// If this Iterable is itself a list, this will be returned directly with no /// copying List asList() { if (this is List) { return this as List; } else { return toList(); } } } class _ComputeAllMessage { const _ComputeAllMessage(this.callback, this.data); final ComputeCallback callback; final List data; } Future> _computeAllImpl(_ComputeAllMessage message) async { final result = await Future.wait( message.data.map((e) async => await message.callback(e))); return result; }