IEnumerableExtensions.cs 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace Masuit.Tools;
  10. /// <summary>
  11. ///
  12. /// </summary>
  13. public static class IEnumerableExtensions
  14. {
  15. /// <summary>
  16. /// 按字段属性判等取交集
  17. /// </summary>
  18. /// <typeparam name="TFirst"></typeparam>
  19. /// <typeparam name="TSecond"></typeparam>
  20. /// <param name="second"></param>
  21. /// <param name="condition"></param>
  22. /// <param name="first"></param>
  23. /// <returns></returns>
  24. public static IEnumerable<TFirst> IntersectBy<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, bool> condition)
  25. {
  26. return first.Where(f => second.Any(s => condition(f, s)));
  27. }
  28. /// <summary>
  29. /// 按字段属性判等取交集
  30. /// </summary>
  31. /// <typeparam name="TSource"></typeparam>
  32. /// <typeparam name="TKey"></typeparam>
  33. /// <param name="first"></param>
  34. /// <param name="second"></param>
  35. /// <param name="keySelector"></param>
  36. /// <returns></returns>
  37. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector)
  38. {
  39. return first.IntersectBy(second, keySelector, null);
  40. }
  41. /// <summary>
  42. /// 按字段属性判等取交集
  43. /// </summary>
  44. /// <typeparam name="TSource"></typeparam>
  45. /// <typeparam name="TKey"></typeparam>
  46. /// <param name="first"></param>
  47. /// <param name="second"></param>
  48. /// <param name="keySelector"></param>
  49. /// <param name="comparer"></param>
  50. /// <returns></returns>
  51. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  52. {
  53. if (first == null)
  54. throw new ArgumentNullException(nameof(first));
  55. if (second == null)
  56. throw new ArgumentNullException(nameof(second));
  57. if (keySelector == null)
  58. throw new ArgumentNullException(nameof(keySelector));
  59. return IntersectByIterator(first, second, keySelector, comparer);
  60. }
  61. private static IEnumerable<TSource> IntersectByIterator<TSource, TKey>(IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  62. {
  63. var set = new HashSet<TKey>(second.Select(keySelector), comparer);
  64. foreach (var item in first.Where(source => set.Remove(keySelector(source))))
  65. {
  66. yield return item;
  67. }
  68. }
  69. /// <summary>
  70. /// 多个集合取交集元素
  71. /// </summary>
  72. /// <typeparam name="T"></typeparam>
  73. /// <param name="source"></param>
  74. /// <returns></returns>
  75. public static IEnumerable<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> source)
  76. {
  77. return source.Aggregate((current, item) => current.Intersect(item));
  78. }
  79. /// <summary>
  80. /// 多个集合取交集元素
  81. /// </summary>
  82. /// <typeparam name="TSource"></typeparam>
  83. /// <typeparam name="TKey"></typeparam>
  84. /// <param name="source"></param>
  85. /// <param name="keySelector"></param>
  86. /// <returns></returns>
  87. public static IEnumerable<TSource> IntersectAll<TSource, TKey>(this IEnumerable<IEnumerable<TSource>> source, Func<TSource, TKey> keySelector)
  88. {
  89. return source.Aggregate((current, item) => current.IntersectBy(item, keySelector));
  90. }
  91. /// <summary>
  92. /// 多个集合取交集元素
  93. /// </summary>
  94. /// <typeparam name="TSource"></typeparam>
  95. /// <typeparam name="TKey"></typeparam>
  96. /// <param name="source"></param>
  97. /// <param name="keySelector"></param>
  98. /// <param name="comparer"></param>
  99. /// <returns></returns>
  100. public static IEnumerable<TSource> IntersectAll<TSource, TKey>(this IEnumerable<IEnumerable<TSource>> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  101. {
  102. return source.Aggregate((current, item) => current.IntersectBy(item, keySelector, comparer));
  103. }
  104. /// <summary>
  105. /// 多个集合取交集元素
  106. /// </summary>
  107. /// <typeparam name="T"></typeparam>
  108. /// <param name="source"></param>
  109. /// <param name="comparer"></param>
  110. /// <returns></returns>
  111. public static IEnumerable<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> source, IEqualityComparer<T> comparer)
  112. {
  113. return source.Aggregate((current, item) => current.Intersect(item, comparer));
  114. }
  115. /// <summary>
  116. /// 按字段属性判等取差集
  117. /// </summary>
  118. /// <typeparam name="TFirst"></typeparam>
  119. /// <typeparam name="TSecond"></typeparam>
  120. /// <param name="second"></param>
  121. /// <param name="condition"></param>
  122. /// <param name="first"></param>
  123. /// <returns></returns>
  124. public static IEnumerable<TFirst> ExceptBy<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, bool> condition)
  125. {
  126. return first.Where(f => !second.Any(s => condition(f, s)));
  127. }
  128. #if NET6_0_OR_GREATER
  129. #else
  130. /// <summary>
  131. /// 按字段去重
  132. /// </summary>
  133. /// <typeparam name="TSource"></typeparam>
  134. /// <typeparam name="TKey"></typeparam>
  135. /// <param name="source"></param>
  136. /// <param name="keySelector"></param>
  137. /// <returns></returns>
  138. public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  139. {
  140. if (source == null) throw new ArgumentNullException(nameof(source));
  141. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  142. var set = new HashSet<TKey>();
  143. return source.Where(item => set.Add(keySelector(item)));
  144. }
  145. /// <summary>
  146. /// 按字段属性判等取交集
  147. /// </summary>
  148. /// <typeparam name="TSource"></typeparam>
  149. /// <typeparam name="TKey"></typeparam>
  150. /// <param name="first"></param>
  151. /// <param name="second"></param>
  152. /// <param name="keySelector"></param>
  153. /// <returns></returns>
  154. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector)
  155. {
  156. return first.IntersectBy(second, keySelector, null);
  157. }
  158. /// <summary>
  159. /// 按字段属性判等取交集
  160. /// </summary>
  161. /// <typeparam name="TSource"></typeparam>
  162. /// <typeparam name="TKey"></typeparam>
  163. /// <param name="first"></param>
  164. /// <param name="second"></param>
  165. /// <param name="keySelector"></param>
  166. /// <param name="comparer"></param>
  167. /// <returns></returns>
  168. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  169. {
  170. if (first == null) throw new ArgumentNullException(nameof(first));
  171. if (second == null) throw new ArgumentNullException(nameof(second));
  172. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  173. return IntersectByIterator(first, second, keySelector, comparer);
  174. }
  175. private static IEnumerable<TSource> IntersectByIterator<TSource, TKey>(IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  176. {
  177. var set = new HashSet<TKey>(second, comparer);
  178. return first.Where(source => set.Remove(keySelector(source)));
  179. }
  180. /// <summary>
  181. /// 按字段属性判等取差集
  182. /// </summary>
  183. /// <typeparam name="TSource"></typeparam>
  184. /// <typeparam name="TKey"></typeparam>
  185. /// <param name="first"></param>
  186. /// <param name="second"></param>
  187. /// <param name="keySelector"></param>
  188. /// <returns></returns>
  189. public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector)
  190. {
  191. return first.ExceptBy(second, keySelector, null);
  192. }
  193. /// <summary>
  194. /// 按字段属性判等取差集
  195. /// </summary>
  196. /// <typeparam name="TSource"></typeparam>
  197. /// <typeparam name="TKey"></typeparam>
  198. /// <param name="first"></param>
  199. /// <param name="second"></param>
  200. /// <param name="keySelector"></param>
  201. /// <param name="comparer"></param>
  202. /// <returns></returns>
  203. /// <exception cref="ArgumentNullException"></exception>
  204. public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  205. {
  206. if (first == null) throw new ArgumentNullException(nameof(first));
  207. if (second == null) throw new ArgumentNullException(nameof(second));
  208. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  209. return ExceptByIterator(first, second, keySelector, comparer);
  210. }
  211. private static IEnumerable<TSource> ExceptByIterator<TSource, TKey>(IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  212. {
  213. var set = new HashSet<TKey>(second, comparer);
  214. return first.Where(source => set.Add(keySelector(source)));
  215. }
  216. #endif
  217. /// <summary>
  218. /// 添加多个元素
  219. /// </summary>
  220. /// <typeparam name="T"></typeparam>
  221. /// <param name="this"></param>
  222. /// <param name="values"></param>
  223. public static void AddRange<T>(this ICollection<T> @this, params T[] values)
  224. {
  225. foreach (var obj in values)
  226. {
  227. @this.Add(obj);
  228. }
  229. }
  230. /// <summary>
  231. /// 添加多个元素
  232. /// </summary>
  233. /// <typeparam name="T"></typeparam>
  234. /// <param name="this"></param>
  235. /// <param name="values"></param>
  236. public static void AddRange<T>(this ICollection<T> @this, IEnumerable<T> values)
  237. {
  238. foreach (var obj in values)
  239. {
  240. @this.Add(obj);
  241. }
  242. }
  243. /// <summary>
  244. /// 添加多个元素
  245. /// </summary>
  246. /// <typeparam name="T"></typeparam>
  247. /// <param name="this"></param>
  248. /// <param name="values"></param>
  249. public static void AddRange<T>(this ConcurrentBag<T> @this, params T[] values)
  250. {
  251. foreach (var obj in values)
  252. {
  253. @this.Add(obj);
  254. }
  255. }
  256. /// <summary>
  257. /// 添加多个元素
  258. /// </summary>
  259. /// <typeparam name="T"></typeparam>
  260. /// <param name="this"></param>
  261. /// <param name="values"></param>
  262. public static void AddRange<T>(this ConcurrentQueue<T> @this, params T[] values)
  263. {
  264. foreach (var obj in values)
  265. {
  266. @this.Enqueue(obj);
  267. }
  268. }
  269. /// <summary>
  270. /// 添加符合条件的多个元素
  271. /// </summary>
  272. /// <typeparam name="T"></typeparam>
  273. /// <param name="this"></param>
  274. /// <param name="predicate"></param>
  275. /// <param name="values"></param>
  276. public static void AddRangeIf<T>(this ICollection<T> @this, Func<T, bool> predicate, params T[] values)
  277. {
  278. foreach (var obj in values.Where(predicate))
  279. {
  280. @this.Add(obj);
  281. }
  282. }
  283. /// <summary>
  284. /// 添加符合条件的多个元素
  285. /// </summary>
  286. /// <typeparam name="T"></typeparam>
  287. /// <param name="this"></param>
  288. /// <param name="predicate"></param>
  289. /// <param name="values"></param>
  290. public static void AddRangeIf<T>(this ConcurrentBag<T> @this, Func<T, bool> predicate, params T[] values)
  291. {
  292. foreach (var obj in values.Where(predicate))
  293. {
  294. @this.Add(obj);
  295. }
  296. }
  297. /// <summary>
  298. /// 添加符合条件的多个元素
  299. /// </summary>
  300. /// <typeparam name="T"></typeparam>
  301. /// <param name="this"></param>
  302. /// <param name="predicate"></param>
  303. /// <param name="values"></param>
  304. public static void AddRangeIf<T>(this ConcurrentQueue<T> @this, Func<T, bool> predicate, params T[] values)
  305. {
  306. foreach (var obj in values.Where(predicate))
  307. {
  308. @this.Enqueue(obj);
  309. }
  310. }
  311. /// <summary>
  312. /// 添加不重复的元素
  313. /// </summary>
  314. /// <typeparam name="T"></typeparam>
  315. /// <param name="this"></param>
  316. /// <param name="values"></param>
  317. public static void AddRangeIfNotContains<T>(this ICollection<T> @this, params T[] values)
  318. {
  319. foreach (T obj in values)
  320. {
  321. if ([email protected](obj))
  322. {
  323. @this.Add(obj);
  324. }
  325. }
  326. }
  327. /// <summary>
  328. /// 移除符合条件的元素
  329. /// </summary>
  330. /// <typeparam name="T"></typeparam>
  331. /// <param name="this"></param>
  332. /// <param name="where"></param>
  333. public static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
  334. {
  335. foreach (var obj in @this.Where(where).ToList())
  336. {
  337. @this.Remove(obj);
  338. }
  339. }
  340. /// <summary>
  341. /// 在元素之后添加元素
  342. /// </summary>
  343. /// <typeparam name="T"></typeparam>
  344. /// <param name="list"></param>
  345. /// <param name="condition">条件</param>
  346. /// <param name="value">值</param>
  347. public static void InsertAfter<T>(this IList<T> list, Func<T, bool> condition, T value)
  348. {
  349. foreach (var index in list.Select((item, index) => new
  350. {
  351. item,
  352. index
  353. }).Where(p => condition(p.item)).OrderByDescending(p => p.index).Select(t => t.index))
  354. {
  355. if (index + 1 == list.Count)
  356. {
  357. list.Add(value);
  358. }
  359. else
  360. {
  361. list.Insert(index + 1, value);
  362. }
  363. }
  364. }
  365. /// <summary>
  366. /// 在元素之后添加元素
  367. /// </summary>
  368. /// <typeparam name="T"></typeparam>
  369. /// <param name="list"></param>
  370. /// <param name="index">索引位置</param>
  371. /// <param name="value">值</param>
  372. public static void InsertAfter<T>(this IList<T> list, int index, T value)
  373. {
  374. foreach (var i in list.Select((v, i) => new
  375. {
  376. Value = v,
  377. Index = i
  378. }).Where(p => p.Index == index).OrderByDescending(p => p.Index).Select(t => t.Index))
  379. {
  380. if (i + 1 == list.Count)
  381. {
  382. list.Add(value);
  383. }
  384. else
  385. {
  386. list.Insert(i + 1, value);
  387. }
  388. }
  389. }
  390. /// <summary>
  391. /// 转HashSet
  392. /// </summary>
  393. /// <typeparam name="T"></typeparam>
  394. /// <typeparam name="TResult"></typeparam>
  395. /// <param name="source"></param>
  396. /// <param name="selector"></param>
  397. /// <returns></returns>
  398. public static HashSet<TResult> ToHashSet<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector)
  399. {
  400. return new HashSet<TResult>(source.Select(selector));
  401. }
  402. /// <summary>
  403. /// 遍历IEnumerable
  404. /// </summary>
  405. /// <param name="objs"></param>
  406. /// <param name="action">回调方法</param>
  407. /// <typeparam name="T"></typeparam>
  408. public static void ForEach<T>(this IEnumerable<T> objs, Action<T> action)
  409. {
  410. foreach (var o in objs)
  411. {
  412. action(o);
  413. }
  414. }
  415. /// <summary>
  416. /// 异步foreach
  417. /// </summary>
  418. /// <typeparam name="T"></typeparam>
  419. /// <param name="source"></param>
  420. /// <param name="maxParallelCount">最大并行数</param>
  421. /// <param name="action"></param>
  422. /// <param name="cancellationToken"></param>
  423. /// <returns></returns>
  424. public static async Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action, int maxParallelCount, CancellationToken cancellationToken = default)
  425. {
  426. if (Debugger.IsAttached)
  427. {
  428. foreach (var item in source)
  429. {
  430. await action(item);
  431. }
  432. return;
  433. }
  434. var list = new List<Task>();
  435. foreach (var item in source)
  436. {
  437. if (cancellationToken.IsCancellationRequested)
  438. {
  439. return;
  440. }
  441. list.Add(action(item));
  442. if (list.Count(t => !t.IsCompleted) >= maxParallelCount)
  443. {
  444. await Task.WhenAny(list);
  445. list.RemoveAll(t => t.IsCompleted);
  446. }
  447. }
  448. await Task.WhenAll(list);
  449. }
  450. /// <summary>
  451. /// 异步foreach
  452. /// </summary>
  453. /// <typeparam name="T"></typeparam>
  454. /// <param name="source"></param>
  455. /// <param name="action"></param>
  456. /// <param name="cancellationToken"></param>
  457. /// <returns></returns>
  458. public static Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action, CancellationToken cancellationToken = default)
  459. {
  460. if (source is ICollection<T> collection)
  461. {
  462. return ForeachAsync(collection, action, collection.Count, cancellationToken);
  463. }
  464. var list = source.ToList();
  465. return ForeachAsync(list, action, list.Count, cancellationToken);
  466. }
  467. /// <summary>
  468. /// 异步Select
  469. /// </summary>
  470. /// <typeparam name="T"></typeparam>
  471. /// <typeparam name="TResult"></typeparam>
  472. /// <param name="source"></param>
  473. /// <param name="selector"></param>
  474. /// <returns></returns>
  475. public static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector)
  476. {
  477. return Task.WhenAll(source.Select(selector));
  478. }
  479. /// <summary>
  480. /// 异步Select
  481. /// </summary>
  482. /// <typeparam name="T"></typeparam>
  483. /// <typeparam name="TResult"></typeparam>
  484. /// <param name="source"></param>
  485. /// <param name="selector"></param>
  486. /// <returns></returns>
  487. public static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, int, Task<TResult>> selector)
  488. {
  489. return Task.WhenAll(source.Select(selector));
  490. }
  491. /// <summary>
  492. /// 异步Select
  493. /// </summary>
  494. /// <typeparam name="T"></typeparam>
  495. /// <typeparam name="TResult"></typeparam>
  496. /// <param name="source"></param>
  497. /// <param name="selector"></param>
  498. /// <param name="maxParallelCount">最大并行数</param>
  499. /// <returns></returns>
  500. public static async Task<List<TResult>> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector, int maxParallelCount)
  501. {
  502. var results = new List<TResult>();
  503. var tasks = new List<Task<TResult>>();
  504. foreach (var item in source)
  505. {
  506. var task = selector(item);
  507. tasks.Add(task);
  508. if (tasks.Count >= maxParallelCount)
  509. {
  510. await Task.WhenAny(tasks);
  511. var completedTasks = tasks.Where(t => t.IsCompleted).ToArray();
  512. results.AddRange(completedTasks.Select(t => t.Result));
  513. tasks.RemoveWhere(t => completedTasks.Contains(t));
  514. }
  515. }
  516. results.AddRange(await Task.WhenAll(tasks));
  517. return results;
  518. }
  519. /// <summary>
  520. /// 异步Select
  521. /// </summary>
  522. /// <typeparam name="T"></typeparam>
  523. /// <typeparam name="TResult"></typeparam>
  524. /// <param name="source"></param>
  525. /// <param name="selector"></param>
  526. /// <param name="maxParallelCount">最大并行数</param>
  527. /// <returns></returns>
  528. public static async Task<List<TResult>> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, int, Task<TResult>> selector, int maxParallelCount)
  529. {
  530. var results = new List<TResult>();
  531. var tasks = new List<Task<TResult>>();
  532. int index = 0;
  533. foreach (var item in source)
  534. {
  535. var task = selector(item, index);
  536. tasks.Add(task);
  537. Interlocked.Add(ref index, 1);
  538. if (tasks.Count >= maxParallelCount)
  539. {
  540. await Task.WhenAny(tasks);
  541. var completedTasks = tasks.Where(t => t.IsCompleted).ToArray();
  542. results.AddRange(completedTasks.Select(t => t.Result));
  543. tasks.RemoveWhere(t => completedTasks.Contains(t));
  544. }
  545. }
  546. results.AddRange(await Task.WhenAll(tasks));
  547. return results;
  548. }
  549. /// <summary>
  550. /// 异步For
  551. /// </summary>
  552. /// <typeparam name="T"></typeparam>
  553. /// <param name="source"></param>
  554. /// <param name="selector"></param>
  555. /// <param name="maxParallelCount">最大并行数</param>
  556. /// <param name="cancellationToken">取消口令</param>
  557. /// <returns></returns>
  558. public static async Task ForAsync<T>(this IEnumerable<T> source, Func<T, int, Task> selector, int maxParallelCount, CancellationToken cancellationToken = default)
  559. {
  560. int index = 0;
  561. if (Debugger.IsAttached)
  562. {
  563. foreach (var item in source)
  564. {
  565. await selector(item, index);
  566. index++;
  567. }
  568. return;
  569. }
  570. var list = new List<Task>();
  571. foreach (var item in source)
  572. {
  573. if (cancellationToken.IsCancellationRequested)
  574. {
  575. return;
  576. }
  577. list.Add(selector(item, index));
  578. Interlocked.Add(ref index, 1);
  579. if (list.Count >= maxParallelCount)
  580. {
  581. await Task.WhenAny(list);
  582. list.RemoveAll(t => t.IsCompleted);
  583. }
  584. }
  585. await Task.WhenAll(list);
  586. }
  587. /// <summary>
  588. /// 异步For
  589. /// </summary>
  590. /// <typeparam name="T"></typeparam>
  591. /// <param name="source"></param>
  592. /// <param name="selector"></param>
  593. /// <param name="cancellationToken">取消口令</param>
  594. /// <returns></returns>
  595. public static Task ForAsync<T>(this IEnumerable<T> source, Func<T, int, Task> selector, CancellationToken cancellationToken = default)
  596. {
  597. if (source is ICollection<T> collection)
  598. {
  599. return ForAsync(collection, selector, collection.Count, cancellationToken);
  600. }
  601. var list = source.ToList();
  602. return ForAsync(list, selector, list.Count, cancellationToken);
  603. }
  604. /// <summary>
  605. /// 取最大值
  606. /// </summary>
  607. /// <typeparam name="TSource"></typeparam>
  608. /// <typeparam name="TResult"></typeparam>
  609. /// <param name="source"></param>
  610. /// <param name="selector"></param>
  611. /// <returns></returns>
  612. public static TResult MaxOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) => source.Select(selector).DefaultIfEmpty().Max();
  613. /// <summary>
  614. /// 取最大值
  615. /// </summary>
  616. /// <typeparam name="TSource"></typeparam>
  617. /// <typeparam name="TResult"></typeparam>
  618. /// <param name="source"></param>
  619. /// <param name="selector"></param>
  620. /// <param name="defaultValue"></param>
  621. /// <returns></returns>
  622. public static TResult MaxOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max();
  623. /// <summary>
  624. /// 取最大值
  625. /// </summary>
  626. /// <typeparam name="TSource"></typeparam>
  627. /// <param name="source"></param>
  628. /// <returns></returns>
  629. public static TSource MaxOrDefault<TSource>(this IQueryable<TSource> source) => source.DefaultIfEmpty().Max();
  630. /// <summary>
  631. /// 取最大值
  632. /// </summary>
  633. /// <typeparam name="TSource"></typeparam>
  634. /// <param name="source"></param>
  635. /// <param name="defaultValue"></param>
  636. /// <returns></returns>
  637. public static TSource MaxOrDefault<TSource>(this IQueryable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max();
  638. /// <summary>
  639. /// 取最大值
  640. /// </summary>
  641. /// <typeparam name="TSource"></typeparam>
  642. /// <typeparam name="TResult"></typeparam>
  643. /// <param name="source"></param>
  644. /// <param name="selector"></param>
  645. /// <param name="defaultValue"></param>
  646. /// <returns></returns>
  647. public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max();
  648. /// <summary>
  649. /// 取最大值
  650. /// </summary>
  651. /// <typeparam name="TSource"></typeparam>
  652. /// <typeparam name="TResult"></typeparam>
  653. /// <param name="source"></param>
  654. /// <param name="selector"></param>
  655. /// <returns></returns>
  656. public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) => source.Select(selector).DefaultIfEmpty().Max();
  657. /// <summary>
  658. /// 取最大值
  659. /// </summary>
  660. /// <typeparam name="TSource"></typeparam>
  661. /// <param name="source"></param>
  662. /// <returns></returns>
  663. public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source) => source.DefaultIfEmpty().Max();
  664. /// <summary>
  665. /// 取最大值
  666. /// </summary>
  667. /// <typeparam name="TSource"></typeparam>
  668. /// <param name="source"></param>
  669. /// <param name="defaultValue"></param>
  670. /// <returns></returns>
  671. public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max();
  672. /// <summary>
  673. /// 取最小值
  674. /// </summary>
  675. /// <typeparam name="TSource"></typeparam>
  676. /// <typeparam name="TResult"></typeparam>
  677. /// <param name="source"></param>
  678. /// <param name="selector"></param>
  679. /// <returns></returns>
  680. public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) => source.Select(selector).DefaultIfEmpty().Min();
  681. /// <summary>
  682. /// 取最小值
  683. /// </summary>
  684. /// <typeparam name="TSource"></typeparam>
  685. /// <typeparam name="TResult"></typeparam>
  686. /// <param name="source"></param>
  687. /// <param name="selector"></param>
  688. /// <param name="defaultValue"></param>
  689. /// <returns></returns>
  690. public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min();
  691. /// <summary>
  692. /// 取最小值
  693. /// </summary>
  694. /// <typeparam name="TSource"></typeparam>
  695. /// <param name="source"></param>
  696. /// <returns></returns>
  697. public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source) => source.DefaultIfEmpty().Min();
  698. /// <summary>
  699. /// 取最小值
  700. /// </summary>
  701. /// <typeparam name="TSource"></typeparam>
  702. /// <param name="source"></param>
  703. /// <param name="defaultValue"></param>
  704. /// <returns></returns>
  705. public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min();
  706. /// <summary>
  707. /// 取最小值
  708. /// </summary>
  709. /// <typeparam name="TSource"></typeparam>
  710. /// <typeparam name="TResult"></typeparam>
  711. /// <param name="source"></param>
  712. /// <param name="selector"></param>
  713. /// <returns></returns>
  714. public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) => source.Select(selector).DefaultIfEmpty().Min();
  715. /// <summary>
  716. /// 取最小值
  717. /// </summary>
  718. /// <typeparam name="TSource"></typeparam>
  719. /// <typeparam name="TResult"></typeparam>
  720. /// <param name="source"></param>
  721. /// <param name="selector"></param>
  722. /// <param name="defaultValue"></param>
  723. /// <returns></returns>
  724. public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min();
  725. /// <summary>
  726. /// 取最小值
  727. /// </summary>
  728. /// <typeparam name="TSource"></typeparam>
  729. /// <param name="source"></param>
  730. /// <returns></returns>
  731. public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source) => source.DefaultIfEmpty().Min();
  732. /// <summary>
  733. /// 取最小值
  734. /// </summary>
  735. /// <typeparam name="TSource"></typeparam>
  736. /// <param name="source"></param>
  737. /// <param name="defaultValue"></param>
  738. /// <returns></returns>
  739. public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min();
  740. /// <summary>
  741. /// 标准差
  742. /// </summary>
  743. /// <typeparam name="T"></typeparam>
  744. /// <typeparam name="TResult"></typeparam>
  745. /// <param name="source"></param>
  746. /// <param name="selector"></param>
  747. /// <returns></returns>
  748. public static TResult StandardDeviation<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector) where TResult : IConvertible
  749. {
  750. return StandardDeviation(source.Select(t => selector(t).ConvertTo<double>())).ConvertTo<TResult>();
  751. }
  752. /// <summary>
  753. /// 标准差
  754. /// </summary>
  755. /// <typeparam name="T"></typeparam>
  756. /// <param name="source"></param>
  757. /// <returns></returns>
  758. public static T StandardDeviation<T>(this IEnumerable<T> source) where T : IConvertible
  759. {
  760. return StandardDeviation(source.Select(t => t.ConvertTo<double>())).ConvertTo<T>();
  761. }
  762. /// <summary>
  763. /// 标准差
  764. /// </summary>
  765. /// <param name="source"></param>
  766. /// <returns></returns>
  767. public static double StandardDeviation(this IEnumerable<double> source)
  768. {
  769. double result = 0;
  770. var list = source as ICollection<double> ?? source.ToList();
  771. int count = list.Count;
  772. if (count > 1)
  773. {
  774. var avg = list.Average();
  775. var sum = list.Sum(d => (d - avg) * (d - avg));
  776. result = Math.Sqrt(sum / count);
  777. }
  778. return result;
  779. }
  780. /// <summary>
  781. /// 随机排序
  782. /// </summary>
  783. /// <typeparam name="T"></typeparam>
  784. /// <param name="source"></param>
  785. /// <returns></returns>
  786. public static IOrderedEnumerable<T> OrderByRandom<T>(this IEnumerable<T> source)
  787. {
  788. return source.OrderBy(_ => Guid.NewGuid());
  789. }
  790. /// <summary>
  791. /// 序列相等
  792. /// </summary>
  793. /// <typeparam name="T"></typeparam>
  794. /// <param name="first"></param>
  795. /// <param name="second"></param>
  796. /// <param name="condition"></param>
  797. /// <returns></returns>
  798. public static bool SequenceEqual<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> condition)
  799. {
  800. if (first is ICollection<T> source1 && second is ICollection<T> source2)
  801. {
  802. if (source1.Count != source2.Count)
  803. {
  804. return false;
  805. }
  806. if (source1 is IList<T> list1 && source2 is IList<T> list2)
  807. {
  808. int count = source1.Count;
  809. for (int index = 0; index < count; ++index)
  810. {
  811. if (!condition(list1[index], list2[index]))
  812. {
  813. return false;
  814. }
  815. }
  816. return true;
  817. }
  818. }
  819. using IEnumerator<T> enumerator1 = first.GetEnumerator();
  820. using IEnumerator<T> enumerator2 = second.GetEnumerator();
  821. while (enumerator1.MoveNext())
  822. {
  823. if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current))
  824. {
  825. return false;
  826. }
  827. }
  828. return !enumerator2.MoveNext();
  829. }
  830. /// <summary>
  831. /// 序列相等
  832. /// </summary>
  833. /// <typeparam name="T1"></typeparam>
  834. /// <typeparam name="T2"></typeparam>
  835. /// <param name="first"></param>
  836. /// <param name="second"></param>
  837. /// <param name="condition"></param>
  838. /// <returns></returns>
  839. public static bool SequenceEqual<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> condition)
  840. {
  841. if (first is ICollection<T1> source1 && second is ICollection<T2> source2)
  842. {
  843. if (source1.Count != source2.Count)
  844. {
  845. return false;
  846. }
  847. if (source1 is IList<T1> list1 && source2 is IList<T2> list2)
  848. {
  849. int count = source1.Count;
  850. for (int index = 0; index < count; ++index)
  851. {
  852. if (!condition(list1[index], list2[index]))
  853. {
  854. return false;
  855. }
  856. }
  857. return true;
  858. }
  859. }
  860. using IEnumerator<T1> enumerator1 = first.GetEnumerator();
  861. using IEnumerator<T2> enumerator2 = second.GetEnumerator();
  862. while (enumerator1.MoveNext())
  863. {
  864. if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current))
  865. {
  866. return false;
  867. }
  868. }
  869. return !enumerator2.MoveNext();
  870. }
  871. /// <summary>
  872. /// 对比两个集合哪些是新增的、删除的、修改的
  873. /// </summary>
  874. /// <typeparam name="T1"></typeparam>
  875. /// <typeparam name="T2"></typeparam>
  876. /// <param name="first"></param>
  877. /// <param name="second"></param>
  878. /// <param name="condition">对比因素条件</param>
  879. /// <returns></returns>
  880. public static (List<T1> adds, List<T2> remove, List<T1> updates) CompareChanges<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> condition)
  881. {
  882. first ??= new List<T1>();
  883. second ??= new List<T2>();
  884. var firstSource = first as ICollection<T1> ?? first.ToList();
  885. var secondSource = second as ICollection<T2> ?? second.ToList();
  886. var add = firstSource.ExceptBy(secondSource, condition).ToList();
  887. var remove = secondSource.ExceptBy(firstSource, (s, f) => condition(f, s)).ToList();
  888. var update = firstSource.IntersectBy(secondSource, condition).ToList();
  889. return (add, remove, update);
  890. }
  891. /// <summary>
  892. /// 对比两个集合哪些是新增的、删除的、修改的
  893. /// </summary>
  894. /// <typeparam name="T1"></typeparam>
  895. /// <typeparam name="T2"></typeparam>
  896. /// <param name="first"></param>
  897. /// <param name="second"></param>
  898. /// <param name="condition">对比因素条件</param>
  899. /// <returns></returns>
  900. public static (List<T1> adds, List<T2> remove, List<(T1 first, T2 second)> updates) CompareChangesPlus<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> condition)
  901. {
  902. first ??= new List<T1>();
  903. second ??= new List<T2>();
  904. var firstSource = first as ICollection<T1> ?? first.ToList();
  905. var secondSource = second as ICollection<T2> ?? second.ToList();
  906. var add = firstSource.ExceptBy(secondSource, condition).ToList();
  907. var remove = secondSource.ExceptBy(firstSource, (s, f) => condition(f, s)).ToList();
  908. var updates = firstSource.IntersectBy(secondSource, condition).Select(t1 => (t1, secondSource.FirstOrDefault(t2 => condition(t1, t2)))).ToList();
  909. return (add, remove, updates);
  910. }
  911. /// <summary>
  912. /// 将集合声明为非null集合
  913. /// </summary>
  914. /// <typeparam name="T"></typeparam>
  915. /// <param name="list"></param>
  916. /// <returns></returns>
  917. public static List<T> AsNotNull<T>(this List<T> list)
  918. {
  919. return list ?? new List<T>();
  920. }
  921. /// <summary>
  922. /// 将集合声明为非null集合
  923. /// </summary>
  924. /// <typeparam name="T"></typeparam>
  925. /// <param name="list"></param>
  926. /// <returns></returns>
  927. public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> list)
  928. {
  929. return list ?? new List<T>();
  930. }
  931. /// <summary>
  932. /// 满足条件时执行筛选条件
  933. /// </summary>
  934. /// <typeparam name="T"></typeparam>
  935. /// <param name="source"></param>
  936. /// <param name="condition"></param>
  937. /// <param name="where"></param>
  938. /// <returns></returns>
  939. public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, bool condition, Func<T, bool> where)
  940. {
  941. return condition ? source.Where(where) : source;
  942. }
  943. /// <summary>
  944. /// 满足条件时执行筛选条件
  945. /// </summary>
  946. /// <typeparam name="T"></typeparam>
  947. /// <param name="source"></param>
  948. /// <param name="condition"></param>
  949. /// <param name="where"></param>
  950. /// <returns></returns>
  951. public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, Func<bool> condition, Func<T, bool> where)
  952. {
  953. return condition() ? source.Where(where) : source;
  954. }
  955. /// <summary>
  956. /// 满足条件时执行筛选条件
  957. /// </summary>
  958. /// <typeparam name="T"></typeparam>
  959. /// <param name="source"></param>
  960. /// <param name="condition"></param>
  961. /// <param name="where"></param>
  962. /// <returns></returns>
  963. public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, bool condition, Expression<Func<T, bool>> where)
  964. {
  965. return condition ? source.Where(where) : source;
  966. }
  967. /// <summary>
  968. /// 满足条件时执行筛选条件
  969. /// </summary>
  970. /// <typeparam name="T"></typeparam>
  971. /// <param name="source"></param>
  972. /// <param name="condition"></param>
  973. /// <param name="where"></param>
  974. /// <returns></returns>
  975. public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, Func<bool> condition, Expression<Func<T, bool>> where)
  976. {
  977. return condition() ? source.Where(where) : source;
  978. }
  979. /// <summary>
  980. /// 改变元素的索引位置
  981. /// </summary>
  982. /// <typeparam name="T"></typeparam>
  983. /// <param name="list">集合</param>
  984. /// <param name="item">元素</param>
  985. /// <param name="index">索引值</param>
  986. /// <exception cref="ArgumentNullException"></exception>
  987. public static IList<T> ChangeIndex<T>(this IList<T> list, T item, int index)
  988. {
  989. if (item is null)
  990. {
  991. throw new ArgumentNullException(nameof(item));
  992. }
  993. ChangeIndexInternal(list, item, index);
  994. return list;
  995. }
  996. /// <summary>
  997. /// 改变元素的索引位置
  998. /// </summary>
  999. /// <typeparam name="T"></typeparam>
  1000. /// <param name="list">集合</param>
  1001. /// <param name="condition">元素定位条件</param>
  1002. /// <param name="index">索引值</param>
  1003. public static IList<T> ChangeIndex<T>(this IList<T> list, Func<T, bool> condition, int index)
  1004. {
  1005. var item = list.FirstOrDefault(condition);
  1006. if (item != null)
  1007. {
  1008. ChangeIndexInternal(list, item, index);
  1009. }
  1010. return list;
  1011. }
  1012. private static void ChangeIndexInternal<T>(IList<T> list, T item, int index)
  1013. {
  1014. index = Math.Max(0, index);
  1015. index = Math.Min(list.Count - 1, index);
  1016. list.Remove(item);
  1017. list.Insert(index, item);
  1018. }
  1019. }