ToLookup.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerable
  10. {
  11. /// <summary>
  12. /// Creates a lookup from an async-enumerable sequence according to a specified key selector function.
  13. /// </summary>
  14. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  15. /// <typeparam name="TKey">The type of the lookup key computed for each element in the source sequence.</typeparam>
  16. /// <param name="source">An async-enumerable sequence to create a lookup for.</param>
  17. /// <param name="keySelector">A function to extract a key from each element.</param>
  18. /// <param name="cancellationToken">The optional cancellation token to be used for cancelling the sequence at any time.</param>
  19. /// <returns>An async-enumerable sequence containing a single element with a lookup mapping unique key values onto the corresponding source sequence's elements.</returns>
  20. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  21. /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
  22. public static ValueTask<ILookup<TKey, TSource>> ToLookupAsync<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, CancellationToken cancellationToken = default) =>
  23. ToLookupAsync(source, keySelector, comparer: null, cancellationToken);
  24. /// <summary>
  25. /// Creates a lookup from an async-enumerable sequence according to a specified key selector function, and a comparer.
  26. /// </summary>
  27. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  28. /// <typeparam name="TKey">The type of the lookup key computed for each element in the source sequence.</typeparam>
  29. /// <param name="source">An async-enumerable sequence to create a lookup for.</param>
  30. /// <param name="keySelector">A function to extract a key from each element.</param>
  31. /// <param name="comparer">An equality comparer to compare keys.</param>
  32. /// <param name="cancellationToken">The optional cancellation token to be used for cancelling the sequence at any time.</param>
  33. /// <returns>An async-enumerable sequence containing a single element with a lookup mapping unique key values onto the corresponding source sequence's elements.</returns>
  34. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
  35. /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
  36. public static ValueTask<ILookup<TKey, TSource>> ToLookupAsync<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken = default)
  37. {
  38. if (source == null)
  39. throw Error.ArgumentNull(nameof(source));
  40. if (keySelector == null)
  41. throw Error.ArgumentNull(nameof(keySelector));
  42. return Core(source, keySelector, comparer, cancellationToken);
  43. static async ValueTask<ILookup<TKey, TSource>> Core(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken)
  44. {
  45. return await Internal.Lookup<TKey, TSource>.CreateAsync(source, keySelector, comparer, cancellationToken).ConfigureAwait(false);
  46. }
  47. }
  48. internal static ValueTask<ILookup<TKey, TSource>> ToLookupAwaitAsyncCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, CancellationToken cancellationToken = default) =>
  49. ToLookupAwaitAsyncCore<TSource, TKey>(source, keySelector, comparer:null, cancellationToken);
  50. internal static ValueTask<ILookup<TKey, TSource>> ToLookupAwaitAsyncCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken = default)
  51. {
  52. if (source == null)
  53. throw Error.ArgumentNull(nameof(source));
  54. if (keySelector == null)
  55. throw Error.ArgumentNull(nameof(keySelector));
  56. return Core(source, keySelector, comparer, cancellationToken);
  57. static async ValueTask<ILookup<TKey, TSource>> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken)
  58. {
  59. return await Internal.LookupWithTask<TKey, TSource>.CreateAsync(source, keySelector, comparer, cancellationToken).ConfigureAwait(false);
  60. }
  61. }
  62. #if !NO_DEEP_CANCELLATION
  63. internal static ValueTask<ILookup<TKey, TSource>> ToLookupAwaitWithCancellationAsyncCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, CancellationToken cancellationToken = default) =>
  64. ToLookupAwaitWithCancellationAsyncCore(source, keySelector, comparer: null, cancellationToken);
  65. internal static ValueTask<ILookup<TKey, TSource>> ToLookupAwaitWithCancellationAsyncCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken = default)
  66. {
  67. if (source == null)
  68. throw Error.ArgumentNull(nameof(source));
  69. if (keySelector == null)
  70. throw Error.ArgumentNull(nameof(keySelector));
  71. return Core(source, keySelector, comparer, cancellationToken);
  72. static async ValueTask<ILookup<TKey, TSource>> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken)
  73. {
  74. return await Internal.LookupWithTask<TKey, TSource>.CreateAsync(source, keySelector, comparer, cancellationToken).ConfigureAwait(false);
  75. }
  76. }
  77. #endif
  78. /// <summary>
  79. /// Creates a lookup from an async-enumerable sequence according to a specified key selector function, and an element selector function.
  80. /// </summary>
  81. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  82. /// <typeparam name="TKey">The type of the lookup key computed for each element in the source sequence.</typeparam>
  83. /// <typeparam name="TElement">The type of the lookup value computed for each element in the source sequence.</typeparam>
  84. /// <param name="source">An async-enumerable sequence to create a lookup for.</param>
  85. /// <param name="keySelector">A function to extract a key from each element.</param>
  86. /// <param name="elementSelector">A transform function to produce a result element value from each element.</param>
  87. /// <param name="cancellationToken">The optional cancellation token to be used for cancelling the sequence at any time.</param>
  88. /// <returns>An async-enumerable sequence containing a single element with a lookup mapping unique key values onto the corresponding source sequence's elements.</returns>
  89. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="elementSelector"/> is null.</exception>
  90. /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
  91. public static ValueTask<ILookup<TKey, TElement>> ToLookupAsync<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, CancellationToken cancellationToken = default) =>
  92. ToLookupAsync(source, keySelector, elementSelector, comparer: null, cancellationToken);
  93. /// <summary>
  94. /// Creates a lookup from an async-enumerable sequence according to a specified key selector function, a comparer, and an element selector function.
  95. /// </summary>
  96. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  97. /// <typeparam name="TKey">The type of the lookup key computed for each element in the source sequence.</typeparam>
  98. /// <typeparam name="TElement">The type of the lookup value computed for each element in the source sequence.</typeparam>
  99. /// <param name="source">An async-enumerable sequence to create a lookup for.</param>
  100. /// <param name="keySelector">A function to extract a key from each element.</param>
  101. /// <param name="elementSelector">A transform function to produce a result element value from each element.</param>
  102. /// <param name="comparer">An equality comparer to compare keys.</param>
  103. /// <param name="cancellationToken">The optional cancellation token to be used for cancelling the sequence at any time.</param>
  104. /// <returns>An async-enumerable sequence containing a single element with a lookup mapping unique key values onto the corresponding source sequence's elements.</returns>
  105. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="elementSelector"/> or <paramref name="comparer"/> is null.</exception>
  106. /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
  107. public static ValueTask<ILookup<TKey, TElement>> ToLookupAsync<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken = default)
  108. {
  109. if (source == null)
  110. throw Error.ArgumentNull(nameof(source));
  111. if (keySelector == null)
  112. throw Error.ArgumentNull(nameof(keySelector));
  113. if (elementSelector == null)
  114. throw Error.ArgumentNull(nameof(elementSelector));
  115. return Core(source, keySelector, elementSelector, comparer, cancellationToken);
  116. static async ValueTask<ILookup<TKey, TElement>> Core(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken)
  117. {
  118. return await Internal.Lookup<TKey, TElement>.CreateAsync(source, keySelector, elementSelector, comparer, cancellationToken).ConfigureAwait(false);
  119. }
  120. }
  121. internal static ValueTask<ILookup<TKey, TElement>> ToLookupAwaitAsyncCore<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, CancellationToken cancellationToken = default) =>
  122. ToLookupAwaitAsyncCore<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer: null, cancellationToken);
  123. internal static ValueTask<ILookup<TKey, TElement>> ToLookupAwaitAsyncCore<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken = default)
  124. {
  125. if (source == null)
  126. throw Error.ArgumentNull(nameof(source));
  127. if (keySelector == null)
  128. throw Error.ArgumentNull(nameof(keySelector));
  129. if (elementSelector == null)
  130. throw Error.ArgumentNull(nameof(elementSelector));
  131. return Core(source, keySelector, elementSelector, comparer, cancellationToken);
  132. static async ValueTask<ILookup<TKey, TElement>> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken)
  133. {
  134. return await Internal.LookupWithTask<TKey, TElement>.CreateAsync(source, keySelector, elementSelector, comparer, cancellationToken).ConfigureAwait(false);
  135. }
  136. }
  137. #if !NO_DEEP_CANCELLATION
  138. internal static ValueTask<ILookup<TKey, TElement>> ToLookupAwaitWithCancellationAsyncCore<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, CancellationToken cancellationToken = default) =>
  139. ToLookupAwaitWithCancellationAsyncCore(source, keySelector, elementSelector, comparer: null, cancellationToken);
  140. internal static ValueTask<ILookup<TKey, TElement>> ToLookupAwaitWithCancellationAsyncCore<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken = default)
  141. {
  142. if (source == null)
  143. throw Error.ArgumentNull(nameof(source));
  144. if (keySelector == null)
  145. throw Error.ArgumentNull(nameof(keySelector));
  146. if (elementSelector == null)
  147. throw Error.ArgumentNull(nameof(elementSelector));
  148. return Core(source, keySelector, elementSelector, comparer, cancellationToken);
  149. static async ValueTask<ILookup<TKey, TElement>> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey>? comparer, CancellationToken cancellationToken)
  150. {
  151. return await Internal.LookupWithTask<TKey, TElement>.CreateAsync(source, keySelector, elementSelector, comparer, cancellationToken).ConfigureAwait(false);
  152. }
  153. }
  154. #endif
  155. }
  156. }