|
@@ -131,6 +131,50 @@ namespace System.Linq
|
|
|
return ExtremaBy(source, keySelector, (key, minValue) => -comparer.Compare(key, minValue), cancellationToken);
|
|
|
}
|
|
|
|
|
|
+ public static Task<IList<TSource>> MinBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector)
|
|
|
+ {
|
|
|
+ if (source == null)
|
|
|
+ throw new ArgumentNullException(nameof(source));
|
|
|
+ if (keySelector == null)
|
|
|
+ throw new ArgumentNullException(nameof(keySelector));
|
|
|
+
|
|
|
+ return source.MinBy(keySelector, CancellationToken.None);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Task<IList<TSource>> MinBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IComparer<TKey> comparer)
|
|
|
+ {
|
|
|
+ if (source == null)
|
|
|
+ throw new ArgumentNullException(nameof(source));
|
|
|
+ if (keySelector == null)
|
|
|
+ throw new ArgumentNullException(nameof(keySelector));
|
|
|
+ if (comparer == null)
|
|
|
+ throw new ArgumentNullException(nameof(comparer));
|
|
|
+
|
|
|
+ return source.MinBy(keySelector, comparer, CancellationToken.None);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Task<IList<TSource>> MinBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ if (source == null)
|
|
|
+ throw new ArgumentNullException(nameof(source));
|
|
|
+ if (keySelector == null)
|
|
|
+ throw new ArgumentNullException(nameof(keySelector));
|
|
|
+
|
|
|
+ return MinBy(source, keySelector, Comparer<TKey>.Default, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Task<IList<TSource>> MinBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IComparer<TKey> comparer, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ if (source == null)
|
|
|
+ throw new ArgumentNullException(nameof(source));
|
|
|
+ if (keySelector == null)
|
|
|
+ throw new ArgumentNullException(nameof(keySelector));
|
|
|
+ if (comparer == null)
|
|
|
+ throw new ArgumentNullException(nameof(comparer));
|
|
|
+
|
|
|
+ return ExtremaBy(source, keySelector, (key, minValue) => -comparer.Compare(key, minValue), cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
private static async Task<TSource> Min_<TSource>(IAsyncEnumerable<TSource> source, IComparer<TSource> comparer, CancellationToken cancellationToken)
|
|
|
{
|
|
|
return (await MinBy(source, x => x, comparer, cancellationToken).ConfigureAwait(false)).First();
|
|
@@ -175,5 +219,45 @@ namespace System.Linq
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+ private static async Task<IList<TSource>> ExtremaBy<TSource, TKey>(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TKey, TKey, int> compare, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var result = new List<TSource>();
|
|
|
+
|
|
|
+ var e = source.GetAsyncEnumerator();
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (!await e.MoveNextAsync(cancellationToken).ConfigureAwait(false))
|
|
|
+ throw new InvalidOperationException(Strings.NO_ELEMENTS);
|
|
|
+
|
|
|
+ var current = e.Current;
|
|
|
+ var resKey = await keySelector(current).ConfigureAwait(false);
|
|
|
+ result.Add(current);
|
|
|
+
|
|
|
+ while (await e.MoveNextAsync(cancellationToken).ConfigureAwait(false))
|
|
|
+ {
|
|
|
+ var cur = e.Current;
|
|
|
+ var key = await keySelector(cur).ConfigureAwait(false);
|
|
|
+
|
|
|
+ var cmp = compare(key, resKey);
|
|
|
+ if (cmp == 0)
|
|
|
+ {
|
|
|
+ result.Add(cur);
|
|
|
+ }
|
|
|
+ else if (cmp > 0)
|
|
|
+ {
|
|
|
+ result = new List<TSource> { cur };
|
|
|
+ resKey = key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ await e.DisposeAsync().ConfigureAwait(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
}
|
|
|
}
|