You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

808 lines
29 KiB

4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
2 years ago
4 years ago
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.Specialized;
  5. using System.Text;
  6. namespace Apewer
  7. {
  8. /// <summary>集合的实用工具。</summary>
  9. public static class CollectionUtility
  10. {
  11. #region 判断
  12. /// <summary>判断集合为空。</summary>
  13. public static bool IsEmpty<T>(IEnumerable<T> objects)
  14. {
  15. if (objects == null) return true;
  16. if (objects is T[]) return ((T[])objects).LongLength < 1L;
  17. if (objects is ICollection<T>) return ((ICollection<T>)objects).Count < 1;
  18. foreach (var item in objects) return false;
  19. return true;
  20. }
  21. /// <summary>判断集合存在元素。</summary>
  22. public static bool NotEmpty<T>(IEnumerable<T> objects)
  23. {
  24. if (objects == null) return false;
  25. if (objects is T[]) return ((T[])objects).LongLength > 0L;
  26. if (objects is ICollection<T>) return ((ICollection<T>)objects).Count > 0;
  27. foreach (var item in objects) return true;
  28. return false;
  29. }
  30. /// <summary>获取集合中元素的数量。</summary>
  31. public static int Count<T>(IEnumerable<T> objects)
  32. {
  33. if (objects == null) return 0;
  34. var array = objects as T[];
  35. if (array != null) return array.Length;
  36. var collection = objects as ICollection<T>;
  37. if (collection != null) return collection.Count;
  38. var count = 0;
  39. foreach (var cell in objects) count++;
  40. return count;
  41. }
  42. /// <summary>检查集合是否包含 item。</summary>
  43. public static bool Contains<T>(IEnumerable<T> objects, T cell)
  44. {
  45. if (objects == null) return false;
  46. // objects 实现了含有 Contains 方法的接口。
  47. if (objects is ICollection<T>) return ((ICollection<T>)objects).Contains(cell);
  48. // cell 无效。
  49. if (cell == null)
  50. {
  51. foreach (var i in objects)
  52. {
  53. if (i == null) return true;
  54. }
  55. return false;
  56. }
  57. // cell 有效,进行默认比较。
  58. var comparer = EqualityComparer<T>.Default;
  59. foreach (var i in objects)
  60. {
  61. if (comparer.Equals(i, cell)) return true;
  62. }
  63. return false;
  64. }
  65. /// <summary>获取 item 在集合中的偏移位置,不存在时返回 -1。</summary>
  66. public static int IndexOf<T>(IEnumerable<T> objects, T item)
  67. {
  68. if (objects == null) return -1;
  69. if (objects is IList list) return list.IndexOf(item);
  70. if (item == null)
  71. {
  72. if (objects is T[] array)
  73. {
  74. var length = array.Length;
  75. for (var i = 0; i < length; i++)
  76. {
  77. if (array[i] == null) return i;
  78. }
  79. return -1;
  80. }
  81. var index = 0;
  82. foreach (var obj in objects)
  83. {
  84. if (obj == null) return index;
  85. index++;
  86. }
  87. return -1;
  88. }
  89. else
  90. {
  91. var comparer = EqualityComparer<T>.Default;
  92. if (objects is T[] array)
  93. {
  94. var length = array.Length;
  95. for (var i = 0; i < length; i++)
  96. {
  97. if (comparer.Equals(item, array[i])) return i;
  98. }
  99. return -1;
  100. }
  101. var index = 0;
  102. foreach (var obj in objects)
  103. {
  104. if (comparer.Equals(item, obj)) return index;
  105. index++;
  106. }
  107. return -1;
  108. }
  109. }
  110. #endregion
  111. #region 类型转换
  112. /// <summary>转换模型类型。</summary>
  113. public static TDst[] As<TSrc, TDst>(this TSrc[] array) where TDst : class
  114. {
  115. if (array == null) return null;
  116. var count = array.Length;
  117. var output = new TDst[count];
  118. for (var i = 0; i < count; i++)
  119. {
  120. var item = array[i];
  121. if (item == null) continue;
  122. output[i] = item as TDst;
  123. }
  124. return output;
  125. }
  126. /// <summary>转换模型类型。</summary>
  127. public static TDst[] As<TSrc, TDst>(this TSrc[] array, Func<TSrc, TDst> convert)
  128. {
  129. if (convert == null) throw new ArgumentNullException(nameof(convert));
  130. if (array == null) return null;
  131. var count = array.Length;
  132. var output = new TDst[count];
  133. for (var i = 0; i < count; i++)
  134. {
  135. var item = array[i];
  136. if (item == null) continue;
  137. output[i] = convert(item);
  138. }
  139. return output;
  140. }
  141. /// <summary>安全转换为 List&lt;<typeparamref name="T"/>&gt; 对象。可指定排除 NULL 值元素。</summary>
  142. public static List<T> List<T>(IEnumerable<T> objects, bool excludeNull = false)
  143. {
  144. if (objects == null) return new List<T>();
  145. var list = new List<T>();
  146. var collection = objects as ICollection;
  147. if (collection != null)
  148. {
  149. list.AddRange(objects);
  150. }
  151. else
  152. {
  153. var group = 1024;
  154. var added = 0;
  155. var capacity = 0;
  156. if (objects != null)
  157. {
  158. foreach (var item in objects)
  159. {
  160. if (excludeNull && item == null) continue;
  161. if (added == capacity)
  162. {
  163. capacity += group;
  164. list.Capacity = capacity;
  165. }
  166. list.Add(item);
  167. added += 1;
  168. }
  169. }
  170. list.Capacity = added;
  171. }
  172. return list;
  173. }
  174. /// <summary>安全转换为 &lt;<typeparamref name="T"/>&gt;[] 对象。可指定排除 NULL 值元素。</summary>
  175. public static T[] Array<T>(IEnumerable<T> objects, bool excludeNull = false)
  176. {
  177. if (objects == null) return new T[0];
  178. if (objects is T[]) return (T[])objects;
  179. var collection = objects as ICollection;
  180. if (collection != null)
  181. {
  182. var array = new T[collection.Count];
  183. collection.CopyTo(array, 0);
  184. return array;
  185. }
  186. else
  187. {
  188. var group = 1024;
  189. var array = new T[group];
  190. var added = 0;
  191. var capacity = 0;
  192. foreach (var item in objects)
  193. {
  194. if (excludeNull && item == null) continue;
  195. if (added == capacity)
  196. {
  197. capacity += group;
  198. var temp = new T[capacity];
  199. System.Array.Copy(array, 0, temp, 0, added);
  200. array = temp;
  201. }
  202. array[added] = item;
  203. added += 1;
  204. }
  205. if (added < 1 || added == capacity) return array;
  206. var collapsed = new T[added];
  207. System.Array.Copy(array, 0, collapsed, 0, added);
  208. return collapsed;
  209. }
  210. }
  211. /// <summary>生成 StringPairs 对象实例为副本。</summary>
  212. public static StringPairs StringPairs(NameValueCollection @this) => Apewer.StringPairs.From(@this);
  213. /// <summary>转换集合为数组。</summary>
  214. /// <param name="collection"></param>
  215. /// <returns></returns>
  216. public static Dictionary<string, string[]> Dictionary(NameValueCollection collection)
  217. {
  218. if (collection == null) return null;
  219. var count = collection.Count;
  220. var dict = new Dictionary<string, string[]>();
  221. for (var i = 0; i < count; i++)
  222. {
  223. var key = collection.GetKey(i);
  224. var values = collection.GetValues(i);
  225. dict.Add(key, values);
  226. }
  227. return dict;
  228. }
  229. /// <summary>转换集合为字典。</summary>
  230. /// <typeparam name="TKey">字典 Key 的类型。</typeparam>
  231. /// <typeparam name="TValue">字典 Value 的类型。</typeparam>
  232. /// <param name="items">要转换的集合。</param>
  233. /// <param name="key">根据元素获取 Key 的函数。</param>
  234. /// <exception cref="ArgumentNullException"></exception>
  235. public static Dictionary<TKey, TValue> Dictionary<TKey, TValue>(IEnumerable<TValue> items, Func<TValue, TKey> key)
  236. {
  237. if (items == null) throw new ArgumentNullException(nameof(items));
  238. if (key == null) throw new ArgumentNullException(nameof(key));
  239. var dict = new Dictionary<TKey, TValue>();
  240. foreach (var i in items)
  241. {
  242. if (i == null) continue;
  243. var k = key(i);
  244. if (k.IsNull()) continue;
  245. if (dict.ContainsKey(k)) continue;
  246. dict.Add(k, i);
  247. }
  248. return dict;
  249. }
  250. #endregion
  251. #region 修改集合
  252. /// <summary>添加多个元素。</summary>
  253. public static void Add<T>(List<T> list, params T[] items)
  254. {
  255. if (list != null && items != null) list.AddRange(items);
  256. }
  257. /// <summary>添加多个元素。</summary>
  258. public static IList<T> Add<T>(IList<T> list, IEnumerable<T> items)
  259. {
  260. if (list != null && items != null)
  261. {
  262. foreach (var item in items) list.Add(item);
  263. }
  264. return list;
  265. }
  266. /// <summary>添加元素。</summary>
  267. public static bool Add<TKey, TValue>(IList<KeyValuePair<TKey, TValue>> list, TKey key, TValue value)
  268. {
  269. if (list == null) return false;
  270. list.Add(new KeyValuePair<TKey, TValue>(key, value));
  271. return true;
  272. }
  273. /// <summary>对元素去重,且去除 NULL 值。</summary>
  274. public static T[] Distinct<T>(IEnumerable<T> items)
  275. {
  276. if (items == null) throw new ArgumentNullException(nameof(items));
  277. var count = Count(items);
  278. var added = 0;
  279. var array = new T[count];
  280. var comparer = EqualityComparer<T>.Default;
  281. foreach (var item in items)
  282. {
  283. if (item == null) continue;
  284. var contains = false;
  285. foreach (var i in array)
  286. {
  287. if (comparer.Equals(i, item))
  288. {
  289. contains = true;
  290. break;
  291. }
  292. }
  293. if (contains) continue;
  294. array[added] = item;
  295. added++;
  296. }
  297. if (added < count)
  298. {
  299. var temp = new T[added];
  300. System.Array.Copy(array, 0, temp, 0, added);
  301. array = temp;
  302. }
  303. return array;
  304. }
  305. /// <summary>获取可枚举集合的部分元素。</summary>
  306. /// <typeparam name="T">集合元素的类型。</typeparam>
  307. /// <param name="objects">原集合。</param>
  308. /// <param name="skip">在集合前段要跳过的元素数量。</param>
  309. /// <param name="count">要获取的元素数量,指定为负数时不限元素数量。</param>
  310. /// <param name="stuffer">填充器,获取范围超出原集合的部分,使用此方法填充元素;此函数默认返回 <typeparamref name="T"/> 的默认值。</param>
  311. /// <returns>数量符合 count 的数组。</returns>
  312. public static T[] Slice<T>(IEnumerable<T> objects, int skip = 0, int count = -1, Func<T> stuffer = null)
  313. {
  314. if (count == 0) return new T[0];
  315. var ab = new ArrayBuilder<T>();
  316. var added = 0;
  317. if (skip < 0)
  318. {
  319. var end = 0 - skip;
  320. for (var i = 0; i < end; i++)
  321. {
  322. ab.Add(stuffer == null ? default : stuffer());
  323. added++;
  324. if (count > 0 && added == count) return ab.Export();
  325. }
  326. }
  327. if (objects != null)
  328. {
  329. var offset = 0;
  330. foreach (var item in objects)
  331. {
  332. if (offset < skip)
  333. {
  334. offset++;
  335. continue;
  336. }
  337. ab.Add(item);
  338. added++;
  339. offset++;
  340. if (count > 0 && added == count) return ab.Export();
  341. }
  342. }
  343. while (added < count)
  344. {
  345. ab.Add(stuffer == null ? default : stuffer());
  346. added++;
  347. }
  348. return ab.Export();
  349. }
  350. #endregion
  351. #region 排序
  352. /// <summary>对列表中的元素排序。</summary>
  353. public static List<T> Sort<T>(List<T> list, Func<T, T, int> comparison)
  354. {
  355. if (list == null) return null;
  356. if (comparison == null) return list;
  357. list.Sort(new Comparison<T>(comparison));
  358. return list;
  359. }
  360. /// <summary>对数组排序。</summary>
  361. /// <exception cref="NullReferenceException"></exception>
  362. public static T[] Sort<T>(T[] array, Func<T, T, int> comparison)
  363. {
  364. if (array == null) return array;
  365. if (comparison == null) return array;
  366. System.Array.Sort(array, new Comparison<T>(comparison));
  367. return array;
  368. }
  369. /// <summary>获取集合中的第一个元素。可指定失败时的默认返回值。</summary>
  370. public static T First<T>(IEnumerable<T> collection, T failed = default(T))
  371. {
  372. if (collection == null) return failed;
  373. var array = collection as T[];
  374. if (array != null) return array.Length > 0 ? array[0] : failed;
  375. var list = collection as IList<T>;
  376. if (list != null) return list.Count > 0 ? list[0] : failed;
  377. foreach (var item in collection) return item;
  378. return failed;
  379. }
  380. /// <summary>获取集合中的最后一个元素。可指定失败时的默认返回值。</summary>
  381. public static T Last<T>(IEnumerable<T> collection, T failed = default(T))
  382. {
  383. if (collection == null) return failed;
  384. var array = collection as T[];
  385. if (array != null) return array.Length > 0 ? array[array.Length - 1] : failed;
  386. var list = collection as IList<T>;
  387. if (list != null) return list.Count > 0 ? list[list.Count - 1] : failed;
  388. var value = failed;
  389. foreach (var item in collection) value = item;
  390. return value;
  391. }
  392. /// <summary>对数组升序排序。</summary>
  393. /// <exception cref="NullReferenceException"></exception>
  394. public static T[] Ascend<T>(T[] array) where T : IComparable<T>
  395. {
  396. if (array == null) return null;
  397. array.Sort((a, b) => a.CompareTo(b));
  398. return array;
  399. }
  400. /// <summary>对数组升序排序。</summary>
  401. /// <exception cref="NullReferenceException"></exception>
  402. public static List<T> Ascend<T>(List<T> list) where T : IComparable<T>
  403. {
  404. if (list == null) return null;
  405. list.Sort((a, b) => a.CompareTo(b));
  406. return list;
  407. }
  408. /// <summary>对数组升序排序。</summary>
  409. /// <exception cref="NullReferenceException"></exception>
  410. public static void Ascend<T, TProp>(T[] array, Func<T, TProp> func) where TProp : IComparable<TProp>
  411. {
  412. if (array != null && func != null) Sort(array, (a, b) => func(a).CompareTo(func(b)));
  413. }
  414. /// <summary>对数组降序排序。</summary>
  415. /// <exception cref="NullReferenceException"></exception>
  416. public static T[] Descend<T>(T[] array) where T : IComparable<T>
  417. {
  418. if (array == null) return array;
  419. Sort(array, (a, b) => 0 - a.CompareTo(b));
  420. return array;
  421. }
  422. /// <summary>对数组降序排序。</summary>
  423. /// <exception cref="NullReferenceException"></exception>
  424. public static List<T> Descend<T>(List<T> list) where T : IComparable<T>
  425. {
  426. if (list == null) return null;
  427. list.Sort((a, b) => -a.CompareTo(b));
  428. return list;
  429. }
  430. /// <summary>对数组降序排序。</summary>
  431. /// <exception cref="NullReferenceException"></exception>
  432. public static void Descend<T, TProp>(T[] array, Func<T, TProp> func) where TProp : IComparable<TProp>
  433. {
  434. if (array != null && func != null) Sort(array, (a, b) => 0 - func(a).CompareTo(func(b)));
  435. }
  436. /// <summary>对字典中的键排序。</summary>
  437. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TKey, TKey, int> comparison)
  438. {
  439. if (dict == null) return null;
  440. if (comparison == null) return null;
  441. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  442. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Key, b.Key)));
  443. dict.Clear();
  444. foreach (var item in list) dict.Add(item.Key, item.Value);
  445. return dict;
  446. }
  447. /// <summary>对字典中的键排序。</summary>
  448. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> @this) where TKey : IComparable<TKey>
  449. {
  450. return SortKey(@this, (a, b) => a.CompareTo(b));
  451. }
  452. /// <summary>对字典中的值排序。</summary>
  453. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TValue, TValue, int> comparison)
  454. {
  455. if (dict == null) return null;
  456. if (comparison == null) return dict;
  457. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  458. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Value, b.Value)));
  459. dict.Clear();
  460. foreach (var item in list) dict.Add(item.Key, item.Value);
  461. return dict;
  462. }
  463. /// <summary>对字典中的值排序。</summary>
  464. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> @this) where TValue : IComparable<TValue>
  465. {
  466. return SortValue(@this, (a, b) => a.CompareTo(b));
  467. }
  468. #endregion
  469. #region params
  470. internal static object[] ParseParams(object cells)
  471. {
  472. var parsed = new ArrayBuilder<object>();
  473. ParseParams(cells, parsed, 1);
  474. return parsed;
  475. }
  476. static void ParseParams(object cells, ArrayBuilder<object> parsed, int depth)
  477. {
  478. if (cells.IsNull()) return;
  479. if (cells is string str)
  480. {
  481. parsed.Add(cells);
  482. return;
  483. }
  484. if (cells is IList items)
  485. {
  486. if (depth > 64)
  487. {
  488. parsed.Add(nameof(IList));
  489. return;
  490. }
  491. var count = items.Count;
  492. for (var i = 0; i < count; i++)
  493. {
  494. ParseParams(items[i], parsed, depth + 1);
  495. }
  496. return;
  497. }
  498. parsed.Add(cells.ToString());
  499. }
  500. #endregion
  501. #region Find
  502. /// <summary>根据条件筛选,将符合条件的元素组成新数组。</summary>
  503. public static T[] FindAll<T>(this T[] array, Predicate<T> match) => System.Array.FindAll<T>(array, match);
  504. /// <summary>根据条件筛选,找到第一个符合条件的元素。</summary>
  505. public static T Find<T>(this T[] array, Predicate<T> match) => System.Array.Find<T>(array, match);
  506. #endregion
  507. #region Map
  508. /// <summary>遍历集合,转换元素,生成新数组。</summary>
  509. /// <typeparam name="TIn">输入的元素类型。</typeparam>
  510. /// <typeparam name="TOut">输出的元素类型。</typeparam>
  511. /// <param name="collection">要遍历的集合。</param>
  512. /// <param name="selector">转换程序。</param>
  513. /// <returns>新数组的元素类型。</returns>
  514. public static TOut[] Map<TIn, TOut>(this IEnumerable<TIn> collection, Func<TIn, TOut> selector)
  515. {
  516. if (selector == null) throw new ArgumentNullException(nameof(selector));
  517. if (collection == null) return new TOut[0];
  518. if (collection is TIn[] array)
  519. {
  520. var count = array.Length;
  521. var result = new TOut[count];
  522. for (var i = 0; i < count; i++)
  523. {
  524. result[i] = selector.Invoke(array[i]);
  525. }
  526. return result;
  527. }
  528. else
  529. {
  530. var capacity = 0;
  531. var count = 0;
  532. var list = new List<TOut>();
  533. foreach (var item in collection)
  534. {
  535. if (capacity == count)
  536. {
  537. capacity += 1024;
  538. list.Capacity += capacity;
  539. }
  540. list.Add(selector.Invoke(item));
  541. count += 1;
  542. }
  543. return list.ToArray();
  544. }
  545. }
  546. #endregion
  547. #region ForEach
  548. /// <summary>遍历每个元素,执行回调。</summary>
  549. /// <typeparam name="T">元素的类型。</typeparam>
  550. /// <param name="collection">元素的集合。</param>
  551. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  552. public static void ForEach<T>(this IEnumerable<T> collection, Action<T> callback)
  553. {
  554. if (collection == null || callback == null) return;
  555. ForEach<T>(collection, (item, index) =>
  556. {
  557. callback.Invoke(item);
  558. return true;
  559. });
  560. }
  561. /// <summary>遍历每个元素,执行回调。</summary>
  562. /// <typeparam name="T">元素的类型。</typeparam>
  563. /// <param name="collection">元素的集合。</param>
  564. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  565. public static void ForEach<T>(this IEnumerable<T> collection, Action<T, int> callback)
  566. {
  567. if (collection == null || callback == null) return;
  568. ForEach<T>(collection, (item, index) =>
  569. {
  570. callback.Invoke(item, index);
  571. return true;
  572. });
  573. }
  574. /// <summary>遍历每个元素,执行回调。</summary>
  575. /// <typeparam name="T">元素的类型。</typeparam>
  576. /// <param name="collection">元素的集合。</param>
  577. /// <param name="callback">回调。参数为本次遍历的元素。返回 true 将继续遍历,返回 false 打断遍历。</param>
  578. public static void ForEach<T>(this IEnumerable<T> collection, Func<T, bool> callback)
  579. {
  580. if (collection == null || callback == null) return;
  581. ForEach<T>(collection, (item, index) =>
  582. {
  583. var result = callback.Invoke(item);
  584. return result;
  585. });
  586. }
  587. /// <summary>遍历每个元素,执行回调。</summary>
  588. /// <typeparam name="T">元素的类型。</typeparam>
  589. /// <param name="collection">元素的集合。</param>
  590. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。返回 true 将继续遍历,返回 false 打断遍历。</param>
  591. public static void ForEach<T>(this IEnumerable<T> collection, Func<T, int, bool> callback)
  592. {
  593. if (collection == null || callback == null) return;
  594. if (collection is T[] array)
  595. {
  596. var count = array.Length;
  597. for (var i = 0; i < count; i++)
  598. {
  599. var @continue = callback.Invoke(array[i], i);
  600. if (!@continue) break;
  601. }
  602. }
  603. else
  604. {
  605. var index = 0;
  606. foreach (var item in collection)
  607. {
  608. var @continue = callback.Invoke(item, index);
  609. if (!@continue) break;
  610. index += 1;
  611. }
  612. }
  613. }
  614. /// <summary>遍历每个元素,执行回调。</summary>
  615. /// <typeparam name="T">元素的类型。</typeparam>
  616. /// <param name="collection">元素的集合。</param>
  617. /// <param name="limit">每次遍历的元素数量。</param>
  618. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  619. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Action<T[]> callback)
  620. {
  621. if (collection == null || callback == null) return;
  622. ForEach<T>(collection, limit, (items, index) =>
  623. {
  624. callback.Invoke(items);
  625. return true;
  626. });
  627. }
  628. /// <summary>遍历每个元素,执行回调。</summary>
  629. /// <typeparam name="T">元素的类型。</typeparam>
  630. /// <param name="collection">元素的集合。</param>
  631. /// <param name="limit">每次遍历的元素数量。</param>
  632. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  633. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Action<T[], int> callback)
  634. {
  635. if (collection == null || callback == null) return;
  636. ForEach<T>(collection, limit, (items, index) =>
  637. {
  638. callback.Invoke(items, index);
  639. return true;
  640. });
  641. }
  642. /// <summary>遍历每个元素,执行回调。</summary>
  643. /// <typeparam name="T">元素的类型。</typeparam>
  644. /// <param name="collection">元素的集合。</param>
  645. /// <param name="limit">每次遍历的元素数量。</param>
  646. /// <param name="callback">回调。参数为本次遍历的元素。返回 true 将继续遍历,返回 false 打断遍历。</param>
  647. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Func<T[], bool> callback)
  648. {
  649. if (collection == null || callback == null) return;
  650. ForEach<T>(collection, limit, (items, index) =>
  651. {
  652. var result = callback.Invoke(items);
  653. return result;
  654. });
  655. }
  656. /// <summary>遍历每个元素,执行回调。</summary>
  657. /// <typeparam name="T">元素的类型。</typeparam>
  658. /// <param name="collection">元素的集合。</param>
  659. /// <param name="limit">每次遍历的元素数量。</param>
  660. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。返回 true 将继续遍历,返回 false 打断遍历。</param>
  661. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Func<T[], int, bool> callback)
  662. {
  663. if (limit < 1) throw new ArgumentOutOfRangeException(nameof(limit));
  664. if (collection == null) return;
  665. if (callback == null) return;
  666. if (collection is T[] array)
  667. {
  668. var total = array.LongLength;
  669. var start = 0L;
  670. var index = 0;
  671. var length = 0L;
  672. while (start < total)
  673. {
  674. length = limit;
  675. if (start + length > total) length = total - start;
  676. var temp = new T[length];
  677. System.Array.Copy(array, start, temp, 0L, length);
  678. var @continue = callback.Invoke(temp, index);
  679. if (!@continue) break;
  680. start += length;
  681. index += 1;
  682. }
  683. return;
  684. }
  685. else
  686. {
  687. var queue = new Queue<T>(collection);
  688. var index = 0;
  689. while (queue.Count > 0)
  690. {
  691. var list = new List<T>(limit);
  692. while (list.Count < limit && queue.Count > 0) list.Add(queue.Dequeue());
  693. var temp = list.ToArray();
  694. var @continue = callback.Invoke(temp, index);
  695. if (!@continue) break;
  696. index += 1;
  697. }
  698. }
  699. }
  700. #endregion
  701. }
  702. }