IEnumerableExtensions.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace Masuit.Tools
  8. {
  9. public static partial class IEnumerableExtensions
  10. {
  11. /// <summary>
  12. /// 遍历IEnumerable
  13. /// </summary>
  14. /// <param name="objs"></param>
  15. /// <param name="action">回调方法</param>
  16. /// <typeparam name="T"></typeparam>
  17. public static void ForEach<T>(this IEnumerable<T> objs, Action<T> action)
  18. {
  19. foreach (var o in objs)
  20. {
  21. action(o);
  22. }
  23. }
  24. /// <summary>
  25. /// 异步foreach
  26. /// </summary>
  27. /// <typeparam name="T"></typeparam>
  28. /// <param name="source"></param>
  29. /// <param name="maxParallelCount">并行线程数</param>
  30. /// <param name="action"></param>
  31. /// <returns></returns>
  32. public static async Task ForeachAsync<T>(this IEnumerable<T> source, int maxParallelCount, Func<T, Task> action)
  33. {
  34. using SemaphoreSlim completeSemphoreSlim = new(1);
  35. using SemaphoreSlim taskCountLimitsemaphoreSlim = new(maxParallelCount);
  36. await completeSemphoreSlim.WaitAsync();
  37. int runningtaskCount = source.Count();
  38. foreach (var item in source)
  39. {
  40. await taskCountLimitsemaphoreSlim.WaitAsync();
  41. Task.Run(async () =>
  42. {
  43. try
  44. {
  45. await action(item).ContinueWith(_ =>
  46. {
  47. Interlocked.Decrement(ref runningtaskCount);
  48. if (runningtaskCount == 0)
  49. {
  50. completeSemphoreSlim.Release();
  51. }
  52. });
  53. }
  54. finally
  55. {
  56. taskCountLimitsemaphoreSlim.Release();
  57. }
  58. });
  59. }
  60. await completeSemphoreSlim.WaitAsync();
  61. }
  62. /// <summary>
  63. /// 异步foreach
  64. /// </summary>
  65. /// <typeparam name="T"></typeparam>
  66. /// <param name="source"></param>
  67. /// <param name="action"></param>
  68. /// <returns></returns>
  69. public static Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action)
  70. {
  71. return ForeachAsync(source, source.Count(), action);
  72. }
  73. /// <summary>
  74. /// 按字段去重
  75. /// </summary>
  76. /// <typeparam name="TSource"></typeparam>
  77. /// <typeparam name="TKey"></typeparam>
  78. /// <param name="source"></param>
  79. /// <param name="keySelector"></param>
  80. /// <returns></returns>
  81. public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  82. {
  83. var hash = new HashSet<TKey>();
  84. return source.Where(p => hash.Add(keySelector(p)));
  85. }
  86. /// <summary>
  87. /// 添加多个元素
  88. /// </summary>
  89. /// <typeparam name="T"></typeparam>
  90. /// <param name="this"></param>
  91. /// <param name="values"></param>
  92. public static void AddRange<T>(this ICollection<T> @this, params T[] values)
  93. {
  94. foreach (var obj in values)
  95. {
  96. @this.Add(obj);
  97. }
  98. }
  99. /// <summary>
  100. /// 添加符合条件的多个元素
  101. /// </summary>
  102. /// <typeparam name="T"></typeparam>
  103. /// <param name="this"></param>
  104. /// <param name="predicate"></param>
  105. /// <param name="values"></param>
  106. public static void AddRangeIf<T>(this ICollection<T> @this, Func<T, bool> predicate, params T[] values)
  107. {
  108. foreach (var obj in values)
  109. {
  110. if (predicate(obj))
  111. {
  112. @this.Add(obj);
  113. }
  114. }
  115. }
  116. /// <summary>
  117. /// 添加不重复的元素
  118. /// </summary>
  119. /// <typeparam name="T"></typeparam>
  120. /// <param name="this"></param>
  121. /// <param name="values"></param>
  122. public static void AddRangeIfNotContains<T>(this ICollection<T> @this, params T[] values)
  123. {
  124. foreach (T obj in values)
  125. {
  126. if ([email protected](obj))
  127. {
  128. @this.Add(obj);
  129. }
  130. }
  131. }
  132. /// <summary>
  133. /// 移除符合条件的元素
  134. /// </summary>
  135. /// <typeparam name="T"></typeparam>
  136. /// <param name="this"></param>
  137. /// <param name="where"></param>
  138. public static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
  139. {
  140. foreach (var obj in @this.Where(where).ToList())
  141. {
  142. @this.Remove(obj);
  143. }
  144. }
  145. /// <summary>
  146. /// 在元素之后添加元素
  147. /// </summary>
  148. /// <typeparam name="T"></typeparam>
  149. /// <param name="list"></param>
  150. /// <param name="condition">条件</param>
  151. /// <param name="value">值</param>
  152. public static void InsertAfter<T>(this IList<T> list, Func<T, bool> condition, T value)
  153. {
  154. foreach (var item in list.Select((item, index) => new { item, index }).Where(p => condition(p.item)).OrderByDescending(p => p.index))
  155. {
  156. if (item.index + 1 == list.Count)
  157. {
  158. list.Add(value);
  159. }
  160. else
  161. {
  162. list.Insert(item.index + 1, value);
  163. }
  164. }
  165. }
  166. /// <summary>
  167. /// 在元素之后添加元素
  168. /// </summary>
  169. /// <typeparam name="T"></typeparam>
  170. /// <param name="list"></param>
  171. /// <param name="index">索引位置</param>
  172. /// <param name="value">值</param>
  173. public static void InsertAfter<T>(this IList<T> list, int index, T value)
  174. {
  175. foreach (var item in list.Select((v, i) => new { Value = v, Index = i }).Where(p => p.Index == index).OrderByDescending(p => p.Index))
  176. {
  177. if (item.Index + 1 == list.Count)
  178. {
  179. list.Add(value);
  180. }
  181. else
  182. {
  183. list.Insert(item.Index + 1, value);
  184. }
  185. }
  186. }
  187. /// <summary>
  188. /// 转HashSet
  189. /// </summary>
  190. /// <typeparam name="T"></typeparam>
  191. /// <typeparam name="TResult"></typeparam>
  192. /// <param name="source"></param>
  193. /// <param name="selector"></param>
  194. /// <returns></returns>
  195. public static HashSet<TResult> ToHashSet<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector)
  196. {
  197. var set = new HashSet<TResult>();
  198. set.UnionWith(source.Select(selector));
  199. return set;
  200. }
  201. /// <summary>
  202. /// 异步Select
  203. /// </summary>
  204. /// <typeparam name="T"></typeparam>
  205. /// <typeparam name="TResult"></typeparam>
  206. /// <param name="source"></param>
  207. /// <param name="selector"></param>
  208. /// <returns></returns>
  209. public static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector)
  210. {
  211. return Task.WhenAll(source.Select(selector));
  212. }
  213. }
  214. }