IEnumerableExtensions.cs 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Linq.Expressions;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace Masuit.Tools;
  11. /// <summary>
  12. ///
  13. /// </summary>
  14. public static class IEnumerableExtensions
  15. {
  16. #if NETFRAMEWORK
  17. public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item)
  18. {
  19. return source.Concat([item]);
  20. }
  21. #endif
  22. /// <summary>
  23. /// 按字段属性判等取交集
  24. /// </summary>
  25. /// <typeparam name="TFirst"></typeparam>
  26. /// <typeparam name="TSecond"></typeparam>
  27. /// <param name="second"></param>
  28. /// <param name="condition"></param>
  29. /// <param name="first"></param>
  30. /// <returns></returns>
  31. public static IEnumerable<TFirst> IntersectBy<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, bool> condition)
  32. {
  33. return first.Where(f => second.Any(s => condition(f, s)));
  34. }
  35. /// <summary>
  36. /// 按字段属性判等取交集
  37. /// </summary>
  38. /// <typeparam name="TSource"></typeparam>
  39. /// <typeparam name="TKey"></typeparam>
  40. /// <param name="first"></param>
  41. /// <param name="second"></param>
  42. /// <param name="keySelector"></param>
  43. /// <returns></returns>
  44. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector)
  45. {
  46. return first.IntersectBy(second, keySelector, null);
  47. }
  48. /// <summary>
  49. /// 按字段属性判等取交集
  50. /// </summary>
  51. /// <typeparam name="TSource"></typeparam>
  52. /// <typeparam name="TKey"></typeparam>
  53. /// <param name="first"></param>
  54. /// <param name="second"></param>
  55. /// <param name="keySelector"></param>
  56. /// <param name="comparer"></param>
  57. /// <returns></returns>
  58. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  59. {
  60. if (first == null)
  61. throw new ArgumentNullException(nameof(first));
  62. if (second == null)
  63. throw new ArgumentNullException(nameof(second));
  64. if (keySelector == null)
  65. throw new ArgumentNullException(nameof(keySelector));
  66. return IntersectByIterator(first, second, keySelector, comparer);
  67. }
  68. private static IEnumerable<TSource> IntersectByIterator<TSource, TKey>(IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  69. {
  70. var set = new HashSet<TKey>(second.Select(keySelector), comparer);
  71. foreach (var item in first.Where(source => set.Remove(keySelector(source))))
  72. {
  73. yield return item;
  74. }
  75. }
  76. /// <summary>
  77. /// 多个集合取交集元素
  78. /// </summary>
  79. /// <typeparam name="T"></typeparam>
  80. /// <param name="source"></param>
  81. /// <returns></returns>
  82. public static IEnumerable<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> source)
  83. {
  84. return source.Aggregate((current, item) => current.Intersect(item));
  85. }
  86. /// <summary>
  87. /// 多个集合取交集元素
  88. /// </summary>
  89. /// <typeparam name="TSource"></typeparam>
  90. /// <typeparam name="TKey"></typeparam>
  91. /// <param name="source"></param>
  92. /// <param name="keySelector"></param>
  93. /// <returns></returns>
  94. public static IEnumerable<TSource> IntersectAll<TSource, TKey>(this IEnumerable<IEnumerable<TSource>> source, Func<TSource, TKey> keySelector)
  95. {
  96. return source.Aggregate((current, item) => current.IntersectBy(item, keySelector));
  97. }
  98. /// <summary>
  99. /// 多个集合取交集元素
  100. /// </summary>
  101. /// <typeparam name="TSource"></typeparam>
  102. /// <typeparam name="TKey"></typeparam>
  103. /// <param name="source"></param>
  104. /// <param name="keySelector"></param>
  105. /// <param name="comparer"></param>
  106. /// <returns></returns>
  107. public static IEnumerable<TSource> IntersectAll<TSource, TKey>(this IEnumerable<IEnumerable<TSource>> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  108. {
  109. return source.Aggregate((current, item) => current.IntersectBy(item, keySelector, comparer));
  110. }
  111. /// <summary>
  112. /// 多个集合取交集元素
  113. /// </summary>
  114. /// <typeparam name="T"></typeparam>
  115. /// <param name="source"></param>
  116. /// <param name="comparer"></param>
  117. /// <returns></returns>
  118. public static IEnumerable<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> source, IEqualityComparer<T> comparer)
  119. {
  120. return source.Aggregate((current, item) => current.Intersect(item, comparer));
  121. }
  122. /// <summary>
  123. /// 按字段属性判等取差集
  124. /// </summary>
  125. /// <typeparam name="TFirst"></typeparam>
  126. /// <typeparam name="TSecond"></typeparam>
  127. /// <param name="second"></param>
  128. /// <param name="condition"></param>
  129. /// <param name="first"></param>
  130. /// <returns></returns>
  131. public static IEnumerable<TFirst> ExceptBy<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, bool> condition)
  132. {
  133. return first.Where(f => !second.Any(s => condition(f, s)));
  134. }
  135. /// <summary>
  136. /// 按字段属性判等取差集
  137. /// </summary>
  138. /// <param name="second"></param>
  139. /// <param name="first"></param>
  140. /// <param name="keySelector"></param>
  141. /// <returns></returns>
  142. public static IEnumerable<T> ExceptBy<T, TKey>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, TKey> keySelector)
  143. {
  144. // 将 second 集合转换为 HashSet 以提高查找效率
  145. var keys = new HashSet<TKey>(second.Select(keySelector));
  146. // 使用 Lookup 来分组 first 集合,并过滤掉 second 集合中存在的元素
  147. var firstLookup = first.ToLookup(keySelector);
  148. return firstLookup.Where(g => !keys.Contains(g.Key)).SelectMany(grouping => grouping);
  149. }
  150. #if NET6_0_OR_GREATER
  151. #else
  152. /// <summary>
  153. /// 按字段去重
  154. /// </summary>
  155. /// <typeparam name="TSource"></typeparam>
  156. /// <typeparam name="TKey"></typeparam>
  157. /// <param name="source"></param>
  158. /// <param name="keySelector"></param>
  159. /// <returns></returns>
  160. public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  161. {
  162. if (source == null) throw new ArgumentNullException(nameof(source));
  163. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  164. var set = new HashSet<TKey>();
  165. return source.Where(item => set.Add(keySelector(item)));
  166. }
  167. /// <summary>
  168. /// 按字段属性判等取交集
  169. /// </summary>
  170. /// <typeparam name="TSource"></typeparam>
  171. /// <typeparam name="TKey"></typeparam>
  172. /// <param name="first"></param>
  173. /// <param name="second"></param>
  174. /// <param name="keySelector"></param>
  175. /// <returns></returns>
  176. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector)
  177. {
  178. return first.IntersectBy(second, keySelector, null);
  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. /// <param name="comparer"></param>
  189. /// <returns></returns>
  190. public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  191. {
  192. if (first == null) throw new ArgumentNullException(nameof(first));
  193. if (second == null) throw new ArgumentNullException(nameof(second));
  194. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  195. return IntersectByIterator(first, second, keySelector, comparer);
  196. }
  197. private static IEnumerable<TSource> IntersectByIterator<TSource, TKey>(IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  198. {
  199. var set = new HashSet<TKey>(second, comparer);
  200. return first.Where(source => set.Remove(keySelector(source)));
  201. }
  202. /// <summary>
  203. /// 按字段属性判等取差集
  204. /// </summary>
  205. /// <typeparam name="TSource"></typeparam>
  206. /// <typeparam name="TKey"></typeparam>
  207. /// <param name="first"></param>
  208. /// <param name="second"></param>
  209. /// <param name="keySelector"></param>
  210. /// <returns></returns>
  211. public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector)
  212. {
  213. return first.ExceptBy(second, keySelector, null);
  214. }
  215. /// <summary>
  216. /// 按字段属性判等取差集
  217. /// </summary>
  218. /// <typeparam name="TSource"></typeparam>
  219. /// <typeparam name="TKey"></typeparam>
  220. /// <param name="first"></param>
  221. /// <param name="second"></param>
  222. /// <param name="keySelector"></param>
  223. /// <param name="comparer"></param>
  224. /// <returns></returns>
  225. /// <exception cref="ArgumentNullException"></exception>
  226. public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  227. {
  228. if (first == null) throw new ArgumentNullException(nameof(first));
  229. if (second == null) throw new ArgumentNullException(nameof(second));
  230. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  231. return ExceptByIterator(first, second, keySelector, comparer);
  232. }
  233. private static IEnumerable<TSource> ExceptByIterator<TSource, TKey>(IEnumerable<TSource> first, IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  234. {
  235. var set = new HashSet<TKey>(second, comparer);
  236. return first.Where(source => set.Add(keySelector(source)));
  237. }
  238. #endif
  239. /// <summary>
  240. /// 添加多个元素
  241. /// </summary>
  242. /// <typeparam name="T"></typeparam>
  243. /// <param name="this"></param>
  244. /// <param name="values"></param>
  245. public static void AddRange<T>(this ICollection<T> @this, params T[] values)
  246. {
  247. foreach (var obj in values)
  248. {
  249. @this.Add(obj);
  250. }
  251. }
  252. /// <summary>
  253. /// 添加多个元素
  254. /// </summary>
  255. /// <typeparam name="T"></typeparam>
  256. /// <param name="this"></param>
  257. /// <param name="values"></param>
  258. public static void AddRange<T>(this ICollection<T> @this, IEnumerable<T> values)
  259. {
  260. foreach (var obj in values)
  261. {
  262. @this.Add(obj);
  263. }
  264. }
  265. /// <summary>
  266. /// 添加多个元素
  267. /// </summary>
  268. /// <typeparam name="T"></typeparam>
  269. /// <param name="this"></param>
  270. /// <param name="values"></param>
  271. public static void AddRange<T>(this ConcurrentBag<T> @this, params T[] values)
  272. {
  273. foreach (var obj in values)
  274. {
  275. @this.Add(obj);
  276. }
  277. }
  278. /// <summary>
  279. /// 添加多个元素
  280. /// </summary>
  281. /// <typeparam name="T"></typeparam>
  282. /// <param name="this"></param>
  283. /// <param name="values"></param>
  284. public static void AddRange<T>(this ConcurrentQueue<T> @this, params T[] values)
  285. {
  286. foreach (var obj in values)
  287. {
  288. @this.Enqueue(obj);
  289. }
  290. }
  291. /// <summary>
  292. /// 添加符合条件的多个元素
  293. /// </summary>
  294. /// <typeparam name="T"></typeparam>
  295. /// <param name="this"></param>
  296. /// <param name="predicate"></param>
  297. /// <param name="values"></param>
  298. public static void AddRangeIf<T>(this ICollection<T> @this, Func<T, bool> predicate, params T[] values)
  299. {
  300. foreach (var obj in values.Where(predicate))
  301. {
  302. @this.Add(obj);
  303. }
  304. }
  305. /// <summary>
  306. /// 添加符合条件的多个元素
  307. /// </summary>
  308. /// <typeparam name="T"></typeparam>
  309. /// <param name="this"></param>
  310. /// <param name="predicate"></param>
  311. /// <param name="values"></param>
  312. public static void AddRangeIf<T>(this ConcurrentBag<T> @this, Func<T, bool> predicate, params T[] values)
  313. {
  314. foreach (var obj in values.Where(predicate))
  315. {
  316. @this.Add(obj);
  317. }
  318. }
  319. /// <summary>
  320. /// 添加符合条件的多个元素
  321. /// </summary>
  322. /// <typeparam name="T"></typeparam>
  323. /// <param name="this"></param>
  324. /// <param name="predicate"></param>
  325. /// <param name="values"></param>
  326. public static void AddRangeIf<T>(this ConcurrentQueue<T> @this, Func<T, bool> predicate, params T[] values)
  327. {
  328. foreach (var obj in values.Where(predicate))
  329. {
  330. @this.Enqueue(obj);
  331. }
  332. }
  333. /// <summary>
  334. /// 符合条件则添加元素
  335. /// </summary>
  336. /// <typeparam name="T"></typeparam>
  337. /// <param name="this"></param>
  338. /// <param name="predicate"></param>
  339. /// <param name="values"></param>
  340. public static ICollection<T> AddRangeIf<T>(this ICollection<T> @this, Func<bool> predicate, IEnumerable<T> values)
  341. {
  342. if (predicate())
  343. {
  344. foreach (var value in values)
  345. {
  346. @this.Add(value);
  347. }
  348. }
  349. return @this;
  350. }
  351. /// <summary>
  352. /// 符合条件则添加元素
  353. /// </summary>
  354. /// <typeparam name="T"></typeparam>
  355. /// <param name="this"></param>
  356. /// <param name="predicate"></param>
  357. /// <param name="values"></param>
  358. public static ICollection<T> AddRangeIf<T>(this ICollection<T> @this, bool predicate, IEnumerable<T> values)
  359. {
  360. if (predicate)
  361. {
  362. foreach (var value in values)
  363. {
  364. @this.Add(value);
  365. }
  366. }
  367. return @this;
  368. }
  369. /// <summary>
  370. /// 符合条件则添加元素
  371. /// </summary>
  372. /// <typeparam name="T"></typeparam>
  373. /// <param name="this"></param>
  374. /// <param name="predicate"></param>
  375. /// <param name="values"></param>
  376. public static ConcurrentBag<T> AddRangeIf<T>(this ConcurrentBag<T> @this, Func<bool> predicate, IEnumerable<T> values)
  377. {
  378. if (predicate())
  379. {
  380. foreach (var value in values)
  381. {
  382. @this.Add(value);
  383. }
  384. }
  385. return @this;
  386. }
  387. /// <summary>
  388. /// 符合条件则添加元素
  389. /// </summary>
  390. /// <typeparam name="T"></typeparam>
  391. /// <param name="this"></param>
  392. /// <param name="predicate"></param>
  393. /// <param name="values"></param>
  394. public static ConcurrentBag<T> AddRangeIf<T>(this ConcurrentBag<T> @this, bool predicate, IEnumerable<T> values)
  395. {
  396. if (predicate)
  397. {
  398. foreach (var value in values)
  399. {
  400. @this.Add(value);
  401. }
  402. }
  403. return @this;
  404. }
  405. /// <summary>
  406. /// 符合条件则添加元素
  407. /// </summary>
  408. /// <typeparam name="T"></typeparam>
  409. /// <param name="this"></param>
  410. /// <param name="predicate"></param>
  411. /// <param name="values"></param>
  412. public static ConcurrentQueue<T> AddRangeIf<T>(this ConcurrentQueue<T> @this, Func<bool> predicate, IEnumerable<T> values)
  413. {
  414. if (predicate())
  415. {
  416. foreach (var value in values)
  417. {
  418. @this.Enqueue(value);
  419. }
  420. }
  421. return @this;
  422. }
  423. /// <summary>
  424. /// 符合条件则添加元素
  425. /// </summary>
  426. /// <typeparam name="T"></typeparam>
  427. /// <param name="this"></param>
  428. /// <param name="predicate"></param>
  429. /// <param name="values"></param>
  430. public static ConcurrentQueue<T> AddRangeIf<T>(this ConcurrentQueue<T> @this, bool predicate, IEnumerable<T> values)
  431. {
  432. if (predicate)
  433. {
  434. foreach (var value in values)
  435. {
  436. @this.Enqueue(value);
  437. }
  438. }
  439. return @this;
  440. }
  441. /// <summary>
  442. /// 添加不重复的元素
  443. /// </summary>
  444. /// <typeparam name="T"></typeparam>
  445. /// <param name="this"></param>
  446. /// <param name="values"></param>
  447. public static void AddRangeIfNotContains<T>(this ICollection<T> @this, params T[] values)
  448. {
  449. foreach (var obj in values.Where(obj => [email protected](obj)))
  450. {
  451. @this.Add(obj);
  452. }
  453. }
  454. /// <summary>
  455. /// 符合条件则添加一个元素
  456. /// </summary>
  457. /// <typeparam name="T"></typeparam>
  458. /// <param name="this"></param>
  459. /// <param name="predicate"></param>
  460. /// <param name="value"></param>
  461. public static ICollection<T> AppendIf<T>(this ICollection<T> @this, Func<bool> predicate, T value)
  462. {
  463. if (predicate())
  464. {
  465. @this.Add(value);
  466. }
  467. return @this;
  468. }
  469. /// <summary>
  470. /// 符合条件则添加一个元素
  471. /// </summary>
  472. /// <typeparam name="T"></typeparam>
  473. /// <param name="this"></param>
  474. /// <param name="predicate"></param>
  475. /// <param name="value"></param>
  476. public static ICollection<T> AppendIf<T>(this ICollection<T> @this, bool predicate, T value)
  477. {
  478. if (predicate)
  479. {
  480. @this.Add(value);
  481. }
  482. return @this;
  483. }
  484. /// <summary>
  485. /// 符合条件则添加一个元素
  486. /// </summary>
  487. /// <typeparam name="T"></typeparam>
  488. /// <param name="this"></param>
  489. /// <param name="predicate"></param>
  490. /// <param name="value"></param>
  491. public static IEnumerable<T> AppendIf<T>(this IEnumerable<T> @this, Func<bool> predicate, T value)
  492. {
  493. return predicate() ? @this.Append(value) : @this;
  494. }
  495. /// <summary>
  496. /// 符合条件则添加一个元素
  497. /// </summary>
  498. /// <typeparam name="T"></typeparam>
  499. /// <param name="this"></param>
  500. /// <param name="predicate"></param>
  501. /// <param name="value"></param>
  502. public static IEnumerable<T> AppendIf<T>(this IEnumerable<T> @this, bool predicate, T value)
  503. {
  504. return predicate ? @this.Append(value) : @this;
  505. }
  506. /// <summary>
  507. /// 移除符合条件的元素
  508. /// </summary>
  509. /// <typeparam name="T"></typeparam>
  510. /// <param name="this"></param>
  511. /// <param name="where"></param>
  512. public static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
  513. {
  514. var list = @this.Where(where).ToList();
  515. foreach (var obj in list)
  516. {
  517. @this.Remove(obj);
  518. }
  519. }
  520. /// <summary>
  521. /// 在元素之后添加元素
  522. /// </summary>
  523. /// <typeparam name="T"></typeparam>
  524. /// <param name="list"></param>
  525. /// <param name="condition">条件</param>
  526. /// <param name="value">值</param>
  527. public static void InsertAfter<T>(this IList<T> list, Func<T, bool> condition, T value)
  528. {
  529. foreach (var index in list.Select((item, index) => new
  530. {
  531. item,
  532. index
  533. }).Where(p => condition(p.item)).OrderByDescending(p => p.index).Select(t => t.index))
  534. {
  535. if (index + 1 == list.Count)
  536. {
  537. list.Add(value);
  538. }
  539. else
  540. {
  541. list.Insert(index + 1, value);
  542. }
  543. }
  544. }
  545. /// <summary>
  546. /// 在元素之后添加元素
  547. /// </summary>
  548. /// <typeparam name="T"></typeparam>
  549. /// <param name="list"></param>
  550. /// <param name="index">索引位置</param>
  551. /// <param name="value">值</param>
  552. public static void InsertAfter<T>(this IList<T> list, int index, T value)
  553. {
  554. foreach (var i in list.Select((v, i) => new
  555. {
  556. Value = v,
  557. Index = i
  558. }).Where(p => p.Index == index).OrderByDescending(p => p.Index).Select(t => t.Index))
  559. {
  560. if (i + 1 == list.Count)
  561. {
  562. list.Add(value);
  563. }
  564. else
  565. {
  566. list.Insert(i + 1, value);
  567. }
  568. }
  569. }
  570. /// <summary>
  571. /// 转HashSet
  572. /// </summary>
  573. /// <typeparam name="T"></typeparam>
  574. /// <typeparam name="TResult"></typeparam>
  575. /// <param name="source"></param>
  576. /// <param name="selector"></param>
  577. /// <returns></returns>
  578. public static HashSet<TResult> ToHashSet<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector)
  579. {
  580. return new HashSet<TResult>(source.Select(selector));
  581. }
  582. /// <summary>
  583. /// 转SortedSet
  584. /// </summary>
  585. /// <typeparam name="T"></typeparam>
  586. /// <param name="source"></param>
  587. /// <param name="comparer"></param>
  588. /// <returns></returns>
  589. public static SortedSet<T> ToSortedSet<T>(this IEnumerable<T> source, IComparer<T> comparer = null)
  590. {
  591. return comparer == null ? [.. source] : new SortedSet<T>(source, comparer);
  592. }
  593. /// <summary>
  594. /// 转SortedSet
  595. /// </summary>
  596. /// <typeparam name="T"></typeparam>
  597. /// <typeparam name="TResult"></typeparam>
  598. /// <param name="source"></param>
  599. /// <param name="selector"></param>
  600. /// <param name="comparer"></param>
  601. /// <returns></returns>
  602. public static SortedSet<TResult> ToSortedSet<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector, IComparer<TResult> comparer = null)
  603. {
  604. return comparer == null ? [.. source.Select(selector)] : new SortedSet<TResult>(source.Select(selector), comparer);
  605. }
  606. /// <summary>
  607. /// 转Queue
  608. /// </summary>
  609. /// <typeparam name="T"></typeparam>
  610. /// <param name="source"></param>
  611. /// <returns></returns>
  612. public static Queue<T> ToQueue<T>(this IEnumerable<T> source)
  613. {
  614. return new Queue<T>(source);
  615. }
  616. /// <summary>
  617. /// 转Queue
  618. /// </summary>
  619. /// <typeparam name="T"></typeparam>
  620. /// <typeparam name="TResult"></typeparam>
  621. /// <param name="source"></param>
  622. /// <param name="selector"></param>
  623. /// <returns></returns>
  624. public static Queue<TResult> ToQueue<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector)
  625. {
  626. return new Queue<TResult>(source.Select(selector));
  627. }
  628. /// <summary>
  629. /// 遍历IEnumerable
  630. /// </summary>
  631. /// <param name="objs"></param>
  632. /// <param name="action">回调方法</param>
  633. /// <typeparam name="T"></typeparam>
  634. public static void ForEach<T>(this IEnumerable<T> objs, Action<T> action)
  635. {
  636. foreach (var o in objs)
  637. {
  638. action(o);
  639. }
  640. }
  641. /// <summary>
  642. /// 异步foreach
  643. /// </summary>
  644. /// <typeparam name="T"></typeparam>
  645. /// <param name="source"></param>
  646. /// <param name="maxParallelCount">最大并行数</param>
  647. /// <param name="action"></param>
  648. /// <param name="cancellationToken"></param>
  649. /// <returns></returns>
  650. public static async Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action, int maxParallelCount, CancellationToken cancellationToken = default)
  651. {
  652. if (Debugger.IsAttached)
  653. {
  654. foreach (var item in source)
  655. {
  656. await action(item);
  657. }
  658. return;
  659. }
  660. var list = new List<Task>();
  661. foreach (var item in source)
  662. {
  663. if (cancellationToken.IsCancellationRequested)
  664. {
  665. return;
  666. }
  667. list.Add(action(item));
  668. if (list.Count(t => !t.IsCompleted) >= maxParallelCount)
  669. {
  670. await Task.WhenAny(list);
  671. list.RemoveAll(t => t.IsCompleted);
  672. }
  673. }
  674. await Task.WhenAll(list);
  675. }
  676. /// <summary>
  677. /// 异步foreach
  678. /// </summary>
  679. /// <typeparam name="T"></typeparam>
  680. /// <param name="source"></param>
  681. /// <param name="action"></param>
  682. /// <param name="cancellationToken"></param>
  683. /// <returns></returns>
  684. public static Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action, CancellationToken cancellationToken = default)
  685. {
  686. if (source is ICollection<T> collection)
  687. {
  688. return ForeachAsync(collection, action, collection.Count, cancellationToken);
  689. }
  690. var list = source.ToList();
  691. return ForeachAsync(list, action, list.Count, cancellationToken);
  692. }
  693. /// <summary>
  694. /// 异步Select
  695. /// </summary>
  696. /// <typeparam name="T"></typeparam>
  697. /// <typeparam name="TResult"></typeparam>
  698. /// <param name="source"></param>
  699. /// <param name="selector"></param>
  700. /// <returns></returns>
  701. public static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector)
  702. {
  703. return Task.WhenAll(source.Select(selector));
  704. }
  705. /// <summary>
  706. /// 异步Select
  707. /// </summary>
  708. /// <typeparam name="T"></typeparam>
  709. /// <typeparam name="TResult"></typeparam>
  710. /// <param name="source"></param>
  711. /// <param name="selector"></param>
  712. /// <returns></returns>
  713. public static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, int, Task<TResult>> selector)
  714. {
  715. return Task.WhenAll(source.Select(selector));
  716. }
  717. /// <summary>
  718. /// 异步Select
  719. /// </summary>
  720. /// <typeparam name="T"></typeparam>
  721. /// <typeparam name="TResult"></typeparam>
  722. /// <param name="source"></param>
  723. /// <param name="selector"></param>
  724. /// <param name="maxParallelCount">最大并行数</param>
  725. /// <param name="cancellationToken"></param>
  726. /// <returns></returns>
  727. public static async Task<List<TResult>> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector, int maxParallelCount, CancellationToken cancellationToken = default)
  728. {
  729. var results = new List<TResult>();
  730. var tasks = new List<Task<TResult>>();
  731. foreach (var item in source)
  732. {
  733. if (cancellationToken.IsCancellationRequested)
  734. {
  735. break;
  736. }
  737. var task = selector(item);
  738. tasks.Add(task);
  739. if (tasks.Count >= maxParallelCount)
  740. {
  741. await Task.WhenAny(tasks);
  742. var completedTasks = tasks.Where(t => t.IsCompleted).ToArray();
  743. results.AddRange(completedTasks.Select(t => t.Result));
  744. tasks.RemoveWhere(t => completedTasks.Contains(t));
  745. }
  746. }
  747. results.AddRange(await Task.WhenAll(tasks));
  748. return results;
  749. }
  750. /// <summary>
  751. /// 异步Select
  752. /// </summary>
  753. /// <typeparam name="T"></typeparam>
  754. /// <typeparam name="TResult"></typeparam>
  755. /// <param name="source"></param>
  756. /// <param name="selector"></param>
  757. /// <param name="maxParallelCount">最大并行数</param>
  758. /// <param name="cancellationToken"></param>
  759. /// <returns></returns>
  760. public static async Task<List<TResult>> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, int, Task<TResult>> selector, int maxParallelCount, CancellationToken cancellationToken = default)
  761. {
  762. var results = new List<TResult>();
  763. var tasks = new List<Task<TResult>>();
  764. int index = 0;
  765. foreach (var item in source)
  766. {
  767. if (cancellationToken.IsCancellationRequested)
  768. {
  769. break;
  770. }
  771. var task = selector(item, index);
  772. tasks.Add(task);
  773. Interlocked.Add(ref index, 1);
  774. if (tasks.Count >= maxParallelCount)
  775. {
  776. await Task.WhenAny(tasks);
  777. var completedTasks = tasks.Where(t => t.IsCompleted).ToArray();
  778. results.AddRange(completedTasks.Select(t => t.Result));
  779. tasks.RemoveWhere(t => completedTasks.Contains(t));
  780. }
  781. }
  782. results.AddRange(await Task.WhenAll(tasks));
  783. return results;
  784. }
  785. /// <summary>
  786. /// 异步SelectMany
  787. /// </summary>
  788. /// <typeparam name="T"></typeparam>
  789. /// <typeparam name="TResult"></typeparam>
  790. /// <param name="source"></param>
  791. /// <param name="selector"></param>
  792. /// <returns></returns>
  793. public static Task<IEnumerable<TResult>> SelectManyAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<IEnumerable<TResult>>> selector)
  794. {
  795. return Task.WhenAll(source.Select(selector)).ContinueWith(t => t.Result.SelectMany(_ => _));
  796. }
  797. /// <summary>
  798. /// 异步SelectMany
  799. /// </summary>
  800. /// <typeparam name="T"></typeparam>
  801. /// <typeparam name="TResult"></typeparam>
  802. /// <param name="source"></param>
  803. /// <param name="selector"></param>
  804. /// <returns></returns>
  805. public static Task<IEnumerable<TResult>> SelectManyAsync<T, TResult>(this IEnumerable<T> source, Func<T, int, Task<IEnumerable<TResult>>> selector)
  806. {
  807. return Task.WhenAll(source.Select(selector)).ContinueWith(t => t.Result.SelectMany(_ => _));
  808. }
  809. /// <summary>
  810. /// 异步SelectMany
  811. /// </summary>
  812. /// <typeparam name="T"></typeparam>
  813. /// <typeparam name="TResult"></typeparam>
  814. /// <param name="source"></param>
  815. /// <param name="selector"></param>
  816. /// <param name="maxParallelCount">最大并行数</param>
  817. /// <param name="cancellationToken"></param>
  818. /// <returns></returns>
  819. public static async Task<List<TResult>> SelectManyAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<IEnumerable<TResult>>> selector, int maxParallelCount, CancellationToken cancellationToken = default)
  820. {
  821. var results = new List<TResult>();
  822. var tasks = new List<Task<IEnumerable<TResult>>>();
  823. foreach (var item in source)
  824. {
  825. if (cancellationToken.IsCancellationRequested)
  826. {
  827. break;
  828. }
  829. var task = selector(item);
  830. tasks.Add(task);
  831. if (tasks.Count >= maxParallelCount)
  832. {
  833. await Task.WhenAny(tasks);
  834. var completedTasks = tasks.Where(t => t.IsCompleted).ToArray();
  835. results.AddRange(completedTasks.SelectMany(t => t.Result));
  836. tasks.RemoveWhere(t => completedTasks.Contains(t));
  837. }
  838. }
  839. results.AddRange(await Task.WhenAll(tasks).ContinueWith(t => t.Result.SelectMany(_ => _), cancellationToken));
  840. return results;
  841. }
  842. /// <summary>
  843. /// 异步SelectMany
  844. /// </summary>
  845. /// <typeparam name="T"></typeparam>
  846. /// <typeparam name="TResult"></typeparam>
  847. /// <param name="source"></param>
  848. /// <param name="selector"></param>
  849. /// <param name="maxParallelCount">最大并行数</param>
  850. /// <param name="cancellationToken"></param>
  851. /// <returns></returns>
  852. public static async Task<List<TResult>> SelectManyAsync<T, TResult>(this IEnumerable<T> source, Func<T, int, Task<IEnumerable<TResult>>> selector, int maxParallelCount, CancellationToken cancellationToken = default)
  853. {
  854. var results = new List<TResult>();
  855. var tasks = new List<Task<IEnumerable<TResult>>>();
  856. int index = 0;
  857. foreach (var item in source)
  858. {
  859. if (cancellationToken.IsCancellationRequested)
  860. {
  861. break;
  862. }
  863. var task = selector(item, index);
  864. tasks.Add(task);
  865. Interlocked.Add(ref index, 1);
  866. if (tasks.Count >= maxParallelCount)
  867. {
  868. await Task.WhenAny(tasks);
  869. var completedTasks = tasks.Where(t => t.IsCompleted).ToArray();
  870. results.AddRange(completedTasks.SelectMany(t => t.Result));
  871. tasks.RemoveWhere(t => completedTasks.Contains(t));
  872. }
  873. }
  874. results.AddRange(await Task.WhenAll(tasks).ContinueWith(t => t.Result.SelectMany(_ => _), cancellationToken));
  875. return results;
  876. }
  877. /// <summary>
  878. /// 异步For
  879. /// </summary>
  880. /// <typeparam name="T"></typeparam>
  881. /// <param name="source"></param>
  882. /// <param name="selector"></param>
  883. /// <param name="maxParallelCount">最大并行数</param>
  884. /// <param name="cancellationToken">取消口令</param>
  885. /// <returns></returns>
  886. public static async Task ForAsync<T>(this IEnumerable<T> source, Func<T, int, Task> selector, int maxParallelCount, CancellationToken cancellationToken = default)
  887. {
  888. int index = 0;
  889. if (Debugger.IsAttached)
  890. {
  891. foreach (var item in source)
  892. {
  893. await selector(item, index);
  894. index++;
  895. }
  896. return;
  897. }
  898. var list = new List<Task>();
  899. foreach (var item in source)
  900. {
  901. if (cancellationToken.IsCancellationRequested)
  902. {
  903. return;
  904. }
  905. list.Add(selector(item, index));
  906. Interlocked.Add(ref index, 1);
  907. if (list.Count >= maxParallelCount)
  908. {
  909. await Task.WhenAny(list);
  910. list.RemoveAll(t => t.IsCompleted);
  911. }
  912. }
  913. await Task.WhenAll(list);
  914. }
  915. /// <summary>
  916. /// 异步For
  917. /// </summary>
  918. /// <typeparam name="T"></typeparam>
  919. /// <param name="source"></param>
  920. /// <param name="selector"></param>
  921. /// <param name="cancellationToken">取消口令</param>
  922. /// <returns></returns>
  923. public static Task ForAsync<T>(this IEnumerable<T> source, Func<T, int, Task> selector, CancellationToken cancellationToken = default)
  924. {
  925. if (source is ICollection<T> collection)
  926. {
  927. return ForAsync(collection, selector, collection.Count, cancellationToken);
  928. }
  929. var list = source.ToList();
  930. return ForAsync(list, selector, list.Count, cancellationToken);
  931. }
  932. /// <summary>
  933. /// 取最大值
  934. /// </summary>
  935. /// <typeparam name="TSource"></typeparam>
  936. /// <typeparam name="TResult"></typeparam>
  937. /// <param name="source"></param>
  938. /// <param name="selector"></param>
  939. /// <returns></returns>
  940. public static TResult MaxOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) => source.Select(selector).DefaultIfEmpty().Max();
  941. /// <summary>
  942. /// 取最大值
  943. /// </summary>
  944. /// <typeparam name="TSource"></typeparam>
  945. /// <typeparam name="TResult"></typeparam>
  946. /// <param name="source"></param>
  947. /// <param name="selector"></param>
  948. /// <param name="defaultValue"></param>
  949. /// <returns></returns>
  950. public static TResult MaxOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max();
  951. /// <summary>
  952. /// 取最大值
  953. /// </summary>
  954. /// <typeparam name="TSource"></typeparam>
  955. /// <param name="source"></param>
  956. /// <returns></returns>
  957. public static TSource MaxOrDefault<TSource>(this IQueryable<TSource> source) => source.DefaultIfEmpty().Max();
  958. /// <summary>
  959. /// 取最大值
  960. /// </summary>
  961. /// <typeparam name="TSource"></typeparam>
  962. /// <param name="source"></param>
  963. /// <param name="defaultValue"></param>
  964. /// <returns></returns>
  965. public static TSource MaxOrDefault<TSource>(this IQueryable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max();
  966. /// <summary>
  967. /// 取最大值
  968. /// </summary>
  969. /// <typeparam name="TSource"></typeparam>
  970. /// <typeparam name="TResult"></typeparam>
  971. /// <param name="source"></param>
  972. /// <param name="selector"></param>
  973. /// <param name="defaultValue"></param>
  974. /// <returns></returns>
  975. public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max();
  976. /// <summary>
  977. /// 取最大值
  978. /// </summary>
  979. /// <typeparam name="TSource"></typeparam>
  980. /// <typeparam name="TResult"></typeparam>
  981. /// <param name="source"></param>
  982. /// <param name="selector"></param>
  983. /// <returns></returns>
  984. public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) => source.Select(selector).DefaultIfEmpty().Max();
  985. /// <summary>
  986. /// 取最大值
  987. /// </summary>
  988. /// <typeparam name="TSource"></typeparam>
  989. /// <param name="source"></param>
  990. /// <returns></returns>
  991. public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source) => source.DefaultIfEmpty().Max();
  992. /// <summary>
  993. /// 取最大值
  994. /// </summary>
  995. /// <typeparam name="TSource"></typeparam>
  996. /// <param name="source"></param>
  997. /// <param name="defaultValue"></param>
  998. /// <returns></returns>
  999. public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max();
  1000. /// <summary>
  1001. /// 取最小值
  1002. /// </summary>
  1003. /// <typeparam name="TSource"></typeparam>
  1004. /// <typeparam name="TResult"></typeparam>
  1005. /// <param name="source"></param>
  1006. /// <param name="selector"></param>
  1007. /// <returns></returns>
  1008. public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) => source.Select(selector).DefaultIfEmpty().Min();
  1009. /// <summary>
  1010. /// 取最小值
  1011. /// </summary>
  1012. /// <typeparam name="TSource"></typeparam>
  1013. /// <typeparam name="TResult"></typeparam>
  1014. /// <param name="source"></param>
  1015. /// <param name="selector"></param>
  1016. /// <param name="defaultValue"></param>
  1017. /// <returns></returns>
  1018. public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min();
  1019. /// <summary>
  1020. /// 取最小值
  1021. /// </summary>
  1022. /// <typeparam name="TSource"></typeparam>
  1023. /// <param name="source"></param>
  1024. /// <returns></returns>
  1025. public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source) => source.DefaultIfEmpty().Min();
  1026. /// <summary>
  1027. /// 取最小值
  1028. /// </summary>
  1029. /// <typeparam name="TSource"></typeparam>
  1030. /// <param name="source"></param>
  1031. /// <param name="defaultValue"></param>
  1032. /// <returns></returns>
  1033. public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min();
  1034. /// <summary>
  1035. /// 取最小值
  1036. /// </summary>
  1037. /// <typeparam name="TSource"></typeparam>
  1038. /// <typeparam name="TResult"></typeparam>
  1039. /// <param name="source"></param>
  1040. /// <param name="selector"></param>
  1041. /// <returns></returns>
  1042. public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) => source.Select(selector).DefaultIfEmpty().Min();
  1043. /// <summary>
  1044. /// 取最小值
  1045. /// </summary>
  1046. /// <typeparam name="TSource"></typeparam>
  1047. /// <typeparam name="TResult"></typeparam>
  1048. /// <param name="source"></param>
  1049. /// <param name="selector"></param>
  1050. /// <param name="defaultValue"></param>
  1051. /// <returns></returns>
  1052. public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min();
  1053. /// <summary>
  1054. /// 取最小值
  1055. /// </summary>
  1056. /// <typeparam name="TSource"></typeparam>
  1057. /// <param name="source"></param>
  1058. /// <returns></returns>
  1059. public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source) => source.DefaultIfEmpty().Min();
  1060. /// <summary>
  1061. /// 取最小值
  1062. /// </summary>
  1063. /// <typeparam name="TSource"></typeparam>
  1064. /// <param name="source"></param>
  1065. /// <param name="defaultValue"></param>
  1066. /// <returns></returns>
  1067. public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min();
  1068. /// <summary>
  1069. /// 标准差
  1070. /// </summary>
  1071. /// <typeparam name="T"></typeparam>
  1072. /// <typeparam name="TResult"></typeparam>
  1073. /// <param name="source"></param>
  1074. /// <param name="selector"></param>
  1075. /// <returns></returns>
  1076. public static TResult StandardDeviation<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector) where TResult : IConvertible
  1077. {
  1078. return StandardDeviation(source.Select(t => selector(t).ConvertTo<double>())).ConvertTo<TResult>();
  1079. }
  1080. /// <summary>
  1081. /// 标准差
  1082. /// </summary>
  1083. /// <typeparam name="T"></typeparam>
  1084. /// <param name="source"></param>
  1085. /// <returns></returns>
  1086. public static T StandardDeviation<T>(this IEnumerable<T> source) where T : IConvertible
  1087. {
  1088. return StandardDeviation(source.Select(t => t.ConvertTo<double>())).ConvertTo<T>();
  1089. }
  1090. /// <summary>
  1091. /// 标准差
  1092. /// </summary>
  1093. /// <param name="source"></param>
  1094. /// <returns></returns>
  1095. public static double StandardDeviation(this IEnumerable<double> source)
  1096. {
  1097. double result = 0;
  1098. var list = source as ICollection<double> ?? source.ToList();
  1099. int count = list.Count;
  1100. if (count > 1)
  1101. {
  1102. var avg = list.Average();
  1103. var sum = list.Sum(d => (d - avg) * (d - avg));
  1104. result = Math.Sqrt(sum / count);
  1105. }
  1106. return result;
  1107. }
  1108. /// <summary>
  1109. /// 随机排序
  1110. /// </summary>
  1111. /// <typeparam name="T"></typeparam>
  1112. /// <param name="source"></param>
  1113. /// <returns></returns>
  1114. public static IOrderedEnumerable<T> OrderByRandom<T>(this IEnumerable<T> source)
  1115. {
  1116. return source.OrderBy(_ => Guid.NewGuid());
  1117. }
  1118. /// <summary>
  1119. /// 序列相等
  1120. /// </summary>
  1121. /// <typeparam name="T"></typeparam>
  1122. /// <param name="first"></param>
  1123. /// <param name="second"></param>
  1124. /// <param name="condition"></param>
  1125. /// <returns></returns>
  1126. public static bool SequenceEqual<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> condition)
  1127. {
  1128. if (first is ICollection<T> source1 && second is ICollection<T> source2)
  1129. {
  1130. if (source1.Count != source2.Count)
  1131. {
  1132. return false;
  1133. }
  1134. if (source1 is IList<T> list1 && source2 is IList<T> list2)
  1135. {
  1136. int count = source1.Count;
  1137. for (int index = 0; index < count; ++index)
  1138. {
  1139. if (!condition(list1[index], list2[index]))
  1140. {
  1141. return false;
  1142. }
  1143. }
  1144. return true;
  1145. }
  1146. }
  1147. using IEnumerator<T> enumerator1 = first.GetEnumerator();
  1148. using IEnumerator<T> enumerator2 = second.GetEnumerator();
  1149. while (enumerator1.MoveNext())
  1150. {
  1151. if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current))
  1152. {
  1153. return false;
  1154. }
  1155. }
  1156. return !enumerator2.MoveNext();
  1157. }
  1158. /// <summary>
  1159. /// 序列相等
  1160. /// </summary>
  1161. /// <typeparam name="T1"></typeparam>
  1162. /// <typeparam name="T2"></typeparam>
  1163. /// <param name="first"></param>
  1164. /// <param name="second"></param>
  1165. /// <param name="condition"></param>
  1166. /// <returns></returns>
  1167. public static bool SequenceEqual<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> condition)
  1168. {
  1169. if (first is ICollection<T1> source1 && second is ICollection<T2> source2)
  1170. {
  1171. if (source1.Count != source2.Count)
  1172. {
  1173. return false;
  1174. }
  1175. if (source1 is IList<T1> list1 && source2 is IList<T2> list2)
  1176. {
  1177. int count = source1.Count;
  1178. for (int index = 0; index < count; ++index)
  1179. {
  1180. if (!condition(list1[index], list2[index]))
  1181. {
  1182. return false;
  1183. }
  1184. }
  1185. return true;
  1186. }
  1187. }
  1188. using IEnumerator<T1> enumerator1 = first.GetEnumerator();
  1189. using IEnumerator<T2> enumerator2 = second.GetEnumerator();
  1190. while (enumerator1.MoveNext())
  1191. {
  1192. if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current))
  1193. {
  1194. return false;
  1195. }
  1196. }
  1197. return !enumerator2.MoveNext();
  1198. }
  1199. /// <summary>
  1200. /// 对比两个集合哪些是新增的、删除的、修改的
  1201. /// </summary>
  1202. /// <param name="first">新集合</param>
  1203. /// <param name="second">旧集合</param>
  1204. /// <returns></returns>
  1205. public static (List<T> adds, List<T> remove, List<T> updates) CompareChanges<T>(this IEnumerable<T> first, IEnumerable<T> second)
  1206. {
  1207. first ??= new List<T>();
  1208. second ??= new List<T>();
  1209. var firstSource = first as ICollection<T> ?? first.ToList();
  1210. var secondSource = second as ICollection<T> ?? second.ToList();
  1211. var add = firstSource.Except(secondSource).ToList();
  1212. var remove = secondSource.Except(firstSource).ToList();
  1213. var update = firstSource.Intersect(secondSource).ToList();
  1214. return (add, remove, update);
  1215. }
  1216. /// <summary>
  1217. /// 对比两个集合哪些是新增的、删除的、修改的
  1218. /// </summary>
  1219. /// <typeparam name="TKey">对比因素</typeparam>
  1220. /// <typeparam name="T"></typeparam>
  1221. /// <param name="first">新集合</param>
  1222. /// <param name="second">旧集合</param>
  1223. /// <param name="keySelector">对比因素(可唯一确定元素的字段)</param>
  1224. /// <returns></returns>
  1225. public static (List<T> adds, List<T> remove, List<T> updates) CompareChanges<T, TKey>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, TKey> keySelector)
  1226. {
  1227. return CompareChanges(first, second, keySelector, keySelector);
  1228. }
  1229. /// <summary>
  1230. /// 对比两个集合哪些是新增的、删除的、修改的(大数据集时性能不佳,请考虑使用其他重载)
  1231. /// </summary>
  1232. /// <typeparam name="T1"></typeparam>
  1233. /// <typeparam name="T2"></typeparam>
  1234. /// <param name="first">新集合</param>
  1235. /// <param name="second">旧集合</param>
  1236. /// <param name="condition">对比因素条件</param>
  1237. /// <returns></returns>
  1238. [Obsolete("大数据集时性能不佳,请考虑使用其他重载")]
  1239. 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)
  1240. {
  1241. if (first == null) throw new ArgumentNullException(nameof(first));
  1242. if (second == null) throw new ArgumentNullException(nameof(second));
  1243. if (condition == null) throw new ArgumentNullException(nameof(condition));
  1244. var adds = new List<T1>();
  1245. var removes = new List<T2>();
  1246. var updates = new List<T1>();
  1247. var secondSet = new HashSet<T2>(second);
  1248. foreach (var item in first)
  1249. {
  1250. var match = secondSet.FirstOrDefault(s => condition(item, s));
  1251. if (match != null)
  1252. {
  1253. updates.Add(item);
  1254. secondSet.Remove(match);
  1255. }
  1256. else
  1257. {
  1258. adds.Add(item);
  1259. }
  1260. }
  1261. removes.AddRange(secondSet);
  1262. return (adds, removes, updates);
  1263. }
  1264. /// <summary>
  1265. /// 对比两个集合哪些是新增的、删除的、修改的
  1266. /// </summary>
  1267. /// <typeparam name="T1">集合1</typeparam>
  1268. /// <typeparam name="T2">集合2</typeparam>
  1269. /// <typeparam name="TKey">对比因素</typeparam>
  1270. /// <param name="first">新集合</param>
  1271. /// <param name="second">旧集合</param>
  1272. /// <param name="firstKeySelector">集合1的对比因素(可唯一确定元素的字段)</param>
  1273. /// <param name="secondKeySelector">集合2的对比因素(可唯一确定元素的字段)</param>
  1274. /// <returns></returns>
  1275. public static (List<T1> adds, List<T2> remove, List<T1> updates) CompareChanges<T1, T2, TKey>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, TKey> firstKeySelector, Func<T2, TKey> secondKeySelector)
  1276. {
  1277. first ??= new List<T1>();
  1278. second ??= new List<T2>();
  1279. var firstLookup = first.ToLookup(firstKeySelector);
  1280. var secondLookup = second.ToLookup(secondKeySelector);
  1281. var adds = new List<T1>();
  1282. var removes = new List<T2>();
  1283. var updates = new List<T1>();
  1284. foreach (var kvp in firstLookup)
  1285. {
  1286. if (secondLookup.Contains(kvp.Key))
  1287. {
  1288. updates.AddRange(kvp);
  1289. }
  1290. else
  1291. {
  1292. adds.AddRange(kvp);
  1293. }
  1294. }
  1295. foreach (var kvp in secondLookup.Where(kvp => !firstLookup.Contains(kvp.Key)))
  1296. {
  1297. removes.AddRange(kvp);
  1298. }
  1299. return (adds, removes, updates);
  1300. }
  1301. /// <summary>
  1302. /// 对比两个集合哪些是新增的、删除的、修改的
  1303. /// </summary>
  1304. /// <param name="first">新集合</param>
  1305. /// <param name="second">旧集合</param>
  1306. /// <returns></returns>
  1307. public static (List<T> adds, List<T> remove, List<(T first, T second)> updates) CompareChangesPlus<T>(this IEnumerable<T> first, IEnumerable<T> second)
  1308. {
  1309. first ??= new List<T>();
  1310. second ??= new List<T>();
  1311. var firstSource = first as ICollection<T> ?? first.ToList();
  1312. var secondSource = second as ICollection<T> ?? second.ToList();
  1313. var add = firstSource.Except(secondSource).ToList();
  1314. var remove = secondSource.Except(firstSource).ToList();
  1315. var updates = firstSource.Intersect(secondSource).Select(t1 => (t1, secondSource.FirstOrDefault(t2 => t1.Equals(t2)))).ToList();
  1316. return (add, remove, updates);
  1317. }
  1318. /// <summary>
  1319. /// 对比两个集合哪些是新增的、删除的、修改的
  1320. /// </summary>
  1321. /// <param name="first">新集合</param>
  1322. /// <param name="second">旧集合</param>
  1323. /// <param name="keySelector">对比因素</param>
  1324. /// <returns></returns>
  1325. public static (List<T> adds, List<T> remove, List<(T first, T second)> updates) CompareChangesPlus<T, TKey>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, TKey> keySelector)
  1326. {
  1327. return CompareChangesPlus(first, second, keySelector, keySelector);
  1328. }
  1329. /// <summary>
  1330. /// 对比两个集合哪些是新增的、删除的、修改的(大数据集时性能不佳,请考虑使用其他重载)
  1331. /// </summary>
  1332. /// <typeparam name="T1"></typeparam>
  1333. /// <typeparam name="T2"></typeparam>
  1334. /// <param name="first">新集合</param>
  1335. /// <param name="second">旧集合</param>
  1336. /// <param name="condition">对比因素条件</param>
  1337. /// <returns></returns>
  1338. [Obsolete("大数据集时性能不佳,请考虑使用其他重载")]
  1339. public static (List<T1> adds, List<T2> remove, List<(T1 first, T2 second)> updates) CompareChangesPlus<T1, T2>(
  1340. this IEnumerable<T1> first,
  1341. IEnumerable<T2> second,
  1342. Func<T1, T2, bool> condition)
  1343. {
  1344. if (first == null) throw new ArgumentNullException(nameof(first));
  1345. if (second == null) throw new ArgumentNullException(nameof(second));
  1346. if (condition == null) throw new ArgumentNullException(nameof(condition));
  1347. var adds = new List<T1>();
  1348. var removes = new List<T2>();
  1349. var updates = new List<(T1 first, T2 second)>();
  1350. var secondSet = new HashSet<T2>(second);
  1351. foreach (var item in first)
  1352. {
  1353. var match = secondSet.FirstOrDefault(s => condition(item, s));
  1354. if (match != null)
  1355. {
  1356. updates.Add((item, match));
  1357. secondSet.Remove(match);
  1358. }
  1359. else
  1360. {
  1361. adds.Add(item);
  1362. }
  1363. }
  1364. removes.AddRange(secondSet);
  1365. return (adds, removes, updates);
  1366. }
  1367. /// <summary>
  1368. /// 对比两个集合哪些是新增的、删除的、修改的
  1369. /// </summary>
  1370. /// <typeparam name="T1"></typeparam>
  1371. /// <typeparam name="T2"></typeparam>
  1372. /// <typeparam name="TKey"></typeparam>
  1373. /// <param name="first">新集合</param>
  1374. /// <param name="second">旧集合</param>
  1375. /// <param name="firstKeySelector">集合1的对比因素(可唯一确定元素的字段)</param>
  1376. /// <param name="secondKeySelector">集合2的对比因素(可唯一确定元素的字段)</param>
  1377. /// <returns></returns>
  1378. public static (List<T1> adds, List<T2> remove, List<(T1 first, T2 second)> updates) CompareChangesPlus<T1, T2, TKey>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, TKey> firstKeySelector, Func<T2, TKey> secondKeySelector)
  1379. {
  1380. first ??= new List<T1>();
  1381. second ??= new List<T2>();
  1382. var lookup1 = first.ToLookup(firstKeySelector);
  1383. var lookup2 = second.ToLookup(secondKeySelector);
  1384. var add = new List<T1>();
  1385. var remove = new List<T2>();
  1386. var updates = new List<(T1 first, T2 second)>();
  1387. foreach (var x in lookup1)
  1388. {
  1389. if (lookup2.Contains(x.Key))
  1390. {
  1391. updates.Add((x.First(), lookup2[x.Key].First()));
  1392. }
  1393. else
  1394. {
  1395. add.AddRange(x);
  1396. }
  1397. }
  1398. foreach (var x in lookup2.Where(x => !lookup1.Contains(x.Key)))
  1399. {
  1400. remove.AddRange(x);
  1401. }
  1402. return (add, remove, updates);
  1403. }
  1404. /// <summary>
  1405. /// 将集合声明为非null集合
  1406. /// </summary>
  1407. /// <typeparam name="T"></typeparam>
  1408. /// <param name="list"></param>
  1409. /// <returns></returns>
  1410. public static List<T> AsNotNull<T>(this List<T> list)
  1411. {
  1412. return list ?? new List<T>();
  1413. }
  1414. /// <summary>
  1415. /// 将集合声明为非null集合
  1416. /// </summary>
  1417. /// <typeparam name="T"></typeparam>
  1418. /// <param name="list"></param>
  1419. /// <returns></returns>
  1420. public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> list)
  1421. {
  1422. return list ?? new List<T>();
  1423. }
  1424. /// <summary>
  1425. /// 满足条件时执行筛选条件
  1426. /// </summary>
  1427. /// <typeparam name="T"></typeparam>
  1428. /// <param name="source"></param>
  1429. /// <param name="condition"></param>
  1430. /// <param name="where"></param>
  1431. /// <returns></returns>
  1432. public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, bool condition, Func<T, bool> where)
  1433. {
  1434. return condition ? source.Where(where) : source;
  1435. }
  1436. /// <summary>
  1437. /// 满足条件时执行筛选条件
  1438. /// </summary>
  1439. /// <typeparam name="T"></typeparam>
  1440. /// <param name="source"></param>
  1441. /// <param name="condition"></param>
  1442. /// <param name="where"></param>
  1443. /// <returns></returns>
  1444. public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, Func<bool> condition, Func<T, bool> where)
  1445. {
  1446. return condition() ? source.Where(where) : source;
  1447. }
  1448. /// <summary>
  1449. /// 满足条件时执行筛选条件
  1450. /// </summary>
  1451. /// <typeparam name="T"></typeparam>
  1452. /// <param name="source"></param>
  1453. /// <param name="condition"></param>
  1454. /// <param name="where"></param>
  1455. /// <returns></returns>
  1456. public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, bool condition, Expression<Func<T, bool>> where)
  1457. {
  1458. return condition ? source.Where(where) : source;
  1459. }
  1460. /// <summary>
  1461. /// 满足条件时执行筛选条件
  1462. /// </summary>
  1463. /// <typeparam name="T"></typeparam>
  1464. /// <param name="source"></param>
  1465. /// <param name="condition"></param>
  1466. /// <param name="where"></param>
  1467. /// <returns></returns>
  1468. public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, Func<bool> condition, Expression<Func<T, bool>> where)
  1469. {
  1470. return condition() ? source.Where(where) : source;
  1471. }
  1472. /// <summary>
  1473. /// 改变元素的索引位置
  1474. /// </summary>
  1475. /// <typeparam name="T"></typeparam>
  1476. /// <param name="list">集合</param>
  1477. /// <param name="item">元素</param>
  1478. /// <param name="index">索引值</param>
  1479. /// <exception cref="ArgumentNullException"></exception>
  1480. public static IList<T> ChangeIndex<T>(this IList<T> list, T item, int index)
  1481. {
  1482. if (item is null)
  1483. {
  1484. throw new ArgumentNullException(nameof(item));
  1485. }
  1486. ChangeIndexInternal(list, item, index);
  1487. return list;
  1488. }
  1489. /// <summary>
  1490. /// 改变元素的索引位置
  1491. /// </summary>
  1492. /// <typeparam name="T"></typeparam>
  1493. /// <param name="list">集合</param>
  1494. /// <param name="condition">元素定位条件</param>
  1495. /// <param name="index">索引值</param>
  1496. public static IList<T> ChangeIndex<T>(this IList<T> list, Func<T, bool> condition, int index)
  1497. {
  1498. var item = list.FirstOrDefault(condition);
  1499. if (item != null)
  1500. {
  1501. ChangeIndexInternal(list, item, index);
  1502. }
  1503. return list;
  1504. }
  1505. private static void ChangeIndexInternal<T>(IList<T> list, T item, int index)
  1506. {
  1507. index = Math.Max(0, index);
  1508. index = Math.Min(list.Count - 1, index);
  1509. list.Remove(item);
  1510. list.Insert(index, item);
  1511. }
  1512. }