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.

981 lines
36 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
6 months ago
4 years ago
6 months ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
8 months 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
12 months 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
8 months ago
2 years ago
8 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 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>清理集合,去除 NULL 值。</summary>
  306. public static T[] Vacuum<T>(this IEnumerable<T> items) => FindAll(items, x => x != null);
  307. /// <summary>获取可枚举集合的部分元素。</summary>
  308. /// <typeparam name="T">集合元素的类型。</typeparam>
  309. /// <param name="objects">原集合。</param>
  310. /// <param name="skip">在集合前段要跳过的元素数量。</param>
  311. /// <param name="count">要获取的元素数量,指定为负数时不限元素数量。</param>
  312. /// <param name="stuffer">填充器,获取范围超出原集合的部分,使用此方法填充元素;此函数默认返回 <typeparamref name="T"/> 的默认值。</param>
  313. /// <returns>数量符合 count 的数组。</returns>
  314. public static T[] Slice<T>(IEnumerable<T> objects, int skip = 0, int count = -1, Func<T> stuffer = null)
  315. {
  316. if (count == 0) return new T[0];
  317. var ab = new ArrayBuilder<T>();
  318. var added = 0;
  319. if (skip < 0)
  320. {
  321. var end = 0 - skip;
  322. for (var i = 0; i < end; i++)
  323. {
  324. ab.Add(stuffer == null ? default : stuffer());
  325. added++;
  326. if (count > 0 && added == count) return ab.Export();
  327. }
  328. }
  329. if (objects != null)
  330. {
  331. var offset = 0;
  332. foreach (var item in objects)
  333. {
  334. if (offset < skip)
  335. {
  336. offset++;
  337. continue;
  338. }
  339. ab.Add(item);
  340. added++;
  341. offset++;
  342. if (count > 0 && added == count) return ab.Export();
  343. }
  344. }
  345. while (added < count)
  346. {
  347. ab.Add(stuffer == null ? default : stuffer());
  348. added++;
  349. }
  350. return ab.Export();
  351. }
  352. /// <summary>在数组尾部增加元素,生成新数组,不修改原数组。</summary>
  353. /// <returns>增加元素后的新数组。</returns>
  354. public static T[] Push<T>(this T[] array, T item)
  355. {
  356. if (array == null) return new T[] { item };
  357. var length = array.Length;
  358. var newArray = new T[length + 1];
  359. if (length > 0) System.Array.Copy(array, 0, newArray, 0, length);
  360. newArray[length] = item;
  361. return newArray;
  362. }
  363. /// <summary>在数组尾部增加元素,生成新数组,不修改原数组。</summary>
  364. /// <returns>增加元素后的新数组。</returns>
  365. public static T[] Push<T>(this T[] array, T[] items)
  366. {
  367. if (array == null) return items ?? new T[0];
  368. if (items == null)
  369. {
  370. var result = new T[array.Length];
  371. array.CopyTo(result, 0);
  372. return result;
  373. }
  374. else
  375. {
  376. var length1 = array.Length;
  377. var length2 = items.Length;
  378. var result = new T[length1 + length2];
  379. if (length1 > 0) System.Array.Copy(array, 0, result, 0, length1);
  380. if (length2 > 0) System.Array.Copy(items, 0, result, length1, length2);
  381. return result;
  382. }
  383. }
  384. /// <summary>在数组头部增加元素,生成新数组,不修改原数组。</summary>
  385. /// <returns>增加元素后的新数组。</returns>
  386. public static T[] Unshift<T>(this T[] array, T item)
  387. {
  388. if (array == null) return new T[] { item };
  389. var length = array.Length;
  390. var newArray = new T[length + 1];
  391. newArray[0] = item;
  392. if (length > 0) System.Array.Copy(array, 0, newArray, 1, length);
  393. return newArray;
  394. }
  395. /// <summary>在数组头部增加元素,生成新数组,不修改原数组。</summary>
  396. /// <returns>增加元素后的新数组。</returns>
  397. public static T[] Unshift<T>(this T[] array, T[] items)
  398. {
  399. if (array == null) return items ?? new T[0];
  400. if (items == null)
  401. {
  402. var result = new T[array.Length];
  403. array.CopyTo(result, 0);
  404. return result;
  405. }
  406. else
  407. {
  408. var length1 = array.Length;
  409. var length2 = items.Length;
  410. var result = new T[length1 + length2];
  411. if (length2 > 0) System.Array.Copy(items, 0, result, 0, length2);
  412. if (length1 > 0) System.Array.Copy(array, 0, result, length2, length1);
  413. return result;
  414. }
  415. }
  416. #endregion
  417. #region 排序
  418. /// <summary>对列表中的元素排序。</summary>
  419. public static List<T> Sort<T>(List<T> list, Func<T, T, int> comparison)
  420. {
  421. if (list == null) return null;
  422. if (comparison == null) return list;
  423. list.Sort(new Comparison<T>(comparison));
  424. return list;
  425. }
  426. /// <summary>对数组排序。</summary>
  427. /// <exception cref="NullReferenceException"></exception>
  428. public static T[] Sort<T>(T[] array, Func<T, T, int> comparison)
  429. {
  430. if (array == null) return array;
  431. if (comparison == null) return array;
  432. System.Array.Sort(array, new Comparison<T>(comparison));
  433. return array;
  434. }
  435. /// <summary>获取集合中的第一个元素。可指定失败时的默认返回值。</summary>
  436. public static T First<T>(IEnumerable<T> collection, T failed = default(T))
  437. {
  438. if (collection == null) return failed;
  439. var array = collection as T[];
  440. if (array != null) return array.Length > 0 ? array[0] : failed;
  441. var list = collection as IList<T>;
  442. if (list != null) return list.Count > 0 ? list[0] : failed;
  443. foreach (var item in collection) return item;
  444. return failed;
  445. }
  446. /// <summary>获取集合中的最后一个元素。可指定失败时的默认返回值。</summary>
  447. public static T Last<T>(IEnumerable<T> collection, T failed = default(T))
  448. {
  449. if (collection == null) return failed;
  450. var array = collection as T[];
  451. if (array != null) return array.Length > 0 ? array[array.Length - 1] : failed;
  452. var list = collection as IList<T>;
  453. if (list != null) return list.Count > 0 ? list[list.Count - 1] : failed;
  454. var value = failed;
  455. foreach (var item in collection) value = item;
  456. return value;
  457. }
  458. /// <summary>对数组升序排序。</summary>
  459. /// <exception cref="NullReferenceException"></exception>
  460. public static T[] Ascend<T>(T[] array) where T : IComparable<T>
  461. {
  462. if (array == null) return null;
  463. array.Sort((a, b) => a.CompareTo(b));
  464. return array;
  465. }
  466. /// <summary>对数组升序排序。</summary>
  467. /// <exception cref="NullReferenceException"></exception>
  468. public static List<T> Ascend<T>(List<T> list) where T : IComparable<T>
  469. {
  470. if (list == null) return null;
  471. list.Sort((a, b) => a.CompareTo(b));
  472. return list;
  473. }
  474. /// <summary>对数组升序排序。</summary>
  475. /// <exception cref="NullReferenceException"></exception>
  476. public static void Ascend<T, TProp>(T[] array, Func<T, TProp> func) where TProp : IComparable<TProp>
  477. {
  478. if (array != null && func != null) Sort(array, (a, b) => func(a).CompareTo(func(b)));
  479. }
  480. /// <summary>对数组降序排序。</summary>
  481. /// <exception cref="NullReferenceException"></exception>
  482. public static T[] Descend<T>(T[] array) where T : IComparable<T>
  483. {
  484. if (array == null) return array;
  485. Sort(array, (a, b) => 0 - a.CompareTo(b));
  486. return array;
  487. }
  488. /// <summary>对数组降序排序。</summary>
  489. /// <exception cref="NullReferenceException"></exception>
  490. public static List<T> Descend<T>(List<T> list) where T : IComparable<T>
  491. {
  492. if (list == null) return null;
  493. list.Sort((a, b) => -a.CompareTo(b));
  494. return list;
  495. }
  496. /// <summary>对数组降序排序。</summary>
  497. /// <exception cref="NullReferenceException"></exception>
  498. public static void Descend<T, TProp>(T[] array, Func<T, TProp> func) where TProp : IComparable<TProp>
  499. {
  500. if (array != null && func != null) Sort(array, (a, b) => 0 - func(a).CompareTo(func(b)));
  501. }
  502. /// <summary>对字典中的键排序。</summary>
  503. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TKey, TKey, int> comparison)
  504. {
  505. if (dict == null) return null;
  506. if (comparison == null) return null;
  507. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  508. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Key, b.Key)));
  509. dict.Clear();
  510. foreach (var item in list) dict.Add(item.Key, item.Value);
  511. return dict;
  512. }
  513. /// <summary>对字典中的键排序。</summary>
  514. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> @this) where TKey : IComparable<TKey>
  515. {
  516. return SortKey(@this, (a, b) => a.CompareTo(b));
  517. }
  518. /// <summary>对字典中的值排序。</summary>
  519. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TValue, TValue, int> comparison)
  520. {
  521. if (dict == null) return null;
  522. if (comparison == null) return dict;
  523. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  524. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Value, b.Value)));
  525. dict.Clear();
  526. foreach (var item in list) dict.Add(item.Key, item.Value);
  527. return dict;
  528. }
  529. /// <summary>对字典中的值排序。</summary>
  530. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> @this) where TValue : IComparable<TValue>
  531. {
  532. return SortValue(@this, (a, b) => a.CompareTo(b));
  533. }
  534. #endregion
  535. #region params
  536. internal static object[] ParseParams(object cells)
  537. {
  538. var parsed = new ArrayBuilder<object>();
  539. ParseParams(cells, parsed, 1);
  540. return parsed;
  541. }
  542. static void ParseParams(object cells, ArrayBuilder<object> parsed, int depth)
  543. {
  544. if (cells.IsNull()) return;
  545. if (cells is string str)
  546. {
  547. parsed.Add(cells);
  548. return;
  549. }
  550. if (cells is IList items)
  551. {
  552. if (depth > 64)
  553. {
  554. parsed.Add(nameof(IList));
  555. return;
  556. }
  557. var count = items.Count;
  558. for (var i = 0; i < count; i++)
  559. {
  560. ParseParams(items[i], parsed, depth + 1);
  561. }
  562. return;
  563. }
  564. parsed.Add(cells.ToString());
  565. }
  566. #endregion
  567. #region Find
  568. /// <summary>根据条件筛选,将符合条件的元素组成新数组。</summary>
  569. public static T[] FindAll<T>(this IEnumerable<T> collection, Predicate<T> match)
  570. {
  571. if (collection == null) new ArgumentNullException(nameof(collection));
  572. if (match == null) throw new ArgumentNullException(nameof(match));
  573. if (collection is T[] array)
  574. {
  575. return System.Array.FindAll<T>(array, match);
  576. }
  577. else if (collection is IList<T> list)
  578. {
  579. var count = list.Count;
  580. var result = new List<T>(count);
  581. for (var i = 0; i < count; i++)
  582. {
  583. var matched = match.Invoke(list[i]);
  584. if (matched) result.Add(list[i]);
  585. }
  586. return result.ToArray();
  587. }
  588. else
  589. {
  590. var result = new List<T>();
  591. foreach (var item in collection)
  592. {
  593. var matched = match.Invoke(item);
  594. if (matched) result.Add(item);
  595. }
  596. return result.ToArray();
  597. }
  598. }
  599. /// <summary>根据条件筛选,找到第一个符合条件的元素。</summary>
  600. public static T Find<T>(this IEnumerable<T> collection, Predicate<T> match)
  601. {
  602. if (collection == null) throw new ArgumentNullException(nameof(collection));
  603. if (match == null) throw new ArgumentNullException(nameof(match));
  604. if (collection is T[] array)
  605. {
  606. return System.Array.Find<T>(array, match);
  607. }
  608. else if (collection is IList<T> list)
  609. {
  610. var count = list.Count;
  611. for (var i = 0; i < count; i++)
  612. {
  613. var matched = match.Invoke(list[i]);
  614. if (matched) return list[i];
  615. }
  616. }
  617. else
  618. {
  619. foreach (var item in collection)
  620. {
  621. var matched = match.Invoke(item);
  622. if (matched) return item;
  623. }
  624. }
  625. return default;
  626. }
  627. #endregion
  628. #region Map
  629. /// <summary>遍历集合,转换元素,生成新数组。</summary>
  630. /// <typeparam name="TIn">输入的元素类型。</typeparam>
  631. /// <typeparam name="TOut">输出的元素类型。</typeparam>
  632. /// <param name="collection">要遍历的集合。</param>
  633. /// <param name="selector">转换程序。</param>
  634. /// <returns>新数组的元素类型。</returns>
  635. public static TOut[] Map<TIn, TOut>(this IEnumerable<TIn> collection, Func<TIn, TOut> selector)
  636. {
  637. if (selector == null) throw new ArgumentNullException(nameof(selector));
  638. if (collection == null) return new TOut[0];
  639. return Map(collection, (item, index) => selector.Invoke(item));
  640. }
  641. /// <summary>遍历集合,转换元素,生成新数组。</summary>
  642. /// <typeparam name="TIn">输入的元素类型。</typeparam>
  643. /// <typeparam name="TOut">输出的元素类型。</typeparam>
  644. /// <param name="collection">要遍历的集合。</param>
  645. /// <param name="selector">转换程序,提供索引参数(从 0 开始)。</param>
  646. /// <returns>新数组的元素类型。</returns>
  647. public static TOut[] Map<TIn, TOut>(this IEnumerable<TIn> collection, Func<TIn, int, TOut> selector)
  648. {
  649. if (selector == null) throw new ArgumentNullException(nameof(selector));
  650. if (collection == null) return new TOut[0];
  651. if (collection is TIn[] array)
  652. {
  653. var count = array.Length;
  654. var result = new TOut[count];
  655. for (var i = 0; i < count; i++)
  656. {
  657. result[i] = selector.Invoke(array[i], i);
  658. }
  659. return result;
  660. }
  661. else
  662. {
  663. var capacity = 0;
  664. var count = 0;
  665. var list = new List<TOut>();
  666. foreach (var item in collection)
  667. {
  668. if (capacity == count)
  669. {
  670. capacity += 1024;
  671. list.Capacity += capacity;
  672. }
  673. list.Add(selector.Invoke(item, count));
  674. count += 1;
  675. }
  676. return list.ToArray();
  677. }
  678. }
  679. #endregion
  680. #region ForEach
  681. /// <summary>遍历每个元素,执行回调。</summary>
  682. /// <typeparam name="T">元素的类型。</typeparam>
  683. /// <param name="collection">元素的集合。</param>
  684. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  685. public static void ForEach<T>(this IEnumerable<T> collection, Action<T> callback)
  686. {
  687. if (collection == null || callback == null) return;
  688. ForEach<T>(collection, (item, index) =>
  689. {
  690. callback.Invoke(item);
  691. return JumpStatement.Continue;
  692. });
  693. }
  694. /// <summary>遍历每个元素,执行回调。</summary>
  695. /// <typeparam name="T">元素的类型。</typeparam>
  696. /// <param name="collection">元素的集合。</param>
  697. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  698. public static void ForEach<T>(this IEnumerable<T> collection, Action<T, int> callback)
  699. {
  700. if (collection == null || callback == null) return;
  701. ForEach<T>(collection, (item, index) =>
  702. {
  703. callback.Invoke(item, index);
  704. return JumpStatement.Continue;
  705. });
  706. }
  707. /// <summary>遍历每个元素,执行回调。</summary>
  708. /// <typeparam name="T">元素的类型。</typeparam>
  709. /// <param name="collection">元素的集合。</param>
  710. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  711. public static void ForEach<T>(this IEnumerable<T> collection, Func<T, JumpStatement> callback)
  712. {
  713. if (collection == null || callback == null) return;
  714. ForEach<T>(collection, (item, index) =>
  715. {
  716. var result = callback.Invoke(item);
  717. return result;
  718. });
  719. }
  720. /// <summary>遍历每个元素,执行回调。</summary>
  721. /// <typeparam name="T">元素的类型。</typeparam>
  722. /// <param name="collection">元素的集合。</param>
  723. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。返回 true 将继续遍历,返回 false 打断遍历。</param>
  724. public static void ForEach<T>(this IEnumerable<T> collection, Func<T, int, JumpStatement> callback)
  725. {
  726. if (collection == null || callback == null) return;
  727. if (collection is T[] array)
  728. {
  729. var count = array.Length;
  730. for (var i = 0; i < count; i++)
  731. {
  732. var jump = callback.Invoke(array[i], i);
  733. if (jump == JumpStatement.Break) break;
  734. }
  735. }
  736. else
  737. {
  738. var index = 0;
  739. foreach (var item in collection)
  740. {
  741. var jump = callback.Invoke(item, index);
  742. if (jump == JumpStatement.Break) break;
  743. index += 1;
  744. }
  745. }
  746. }
  747. /// <summary>遍历每个元素,执行回调。</summary>
  748. /// <typeparam name="T">元素的类型。</typeparam>
  749. /// <param name="collection">元素的集合。</param>
  750. /// <param name="limit">每次遍历的元素数量。</param>
  751. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  752. /// <exception cref="ArgumentOutOfRangeException" />
  753. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Action<T[]> callback)
  754. {
  755. if (collection == null || callback == null) return;
  756. ForEach<T>(collection, limit, (items, index) =>
  757. {
  758. callback.Invoke(items);
  759. return JumpStatement.Continue;
  760. });
  761. }
  762. /// <summary>遍历每个元素,执行回调。</summary>
  763. /// <typeparam name="T">元素的类型。</typeparam>
  764. /// <param name="collection">元素的集合。</param>
  765. /// <param name="limit">每次遍历的元素数量。</param>
  766. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  767. /// <exception cref="ArgumentOutOfRangeException" />
  768. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Action<T[], int> callback)
  769. {
  770. if (collection == null || callback == null) return;
  771. ForEach<T>(collection, limit, (items, index) =>
  772. {
  773. callback.Invoke(items, index);
  774. return JumpStatement.Continue;
  775. });
  776. }
  777. /// <summary>遍历每个元素,执行回调。</summary>
  778. /// <typeparam name="T">元素的类型。</typeparam>
  779. /// <param name="collection">元素的集合。</param>
  780. /// <param name="limit">每次遍历的元素数量。</param>
  781. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  782. /// <exception cref="ArgumentOutOfRangeException" />
  783. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Func<T[], JumpStatement> callback)
  784. {
  785. if (collection == null || callback == null) return;
  786. ForEach<T>(collection, limit, (items, index) =>
  787. {
  788. var result = callback.Invoke(items);
  789. return result;
  790. });
  791. }
  792. /// <summary>遍历每个元素,执行回调。</summary>
  793. /// <typeparam name="T">元素的类型。</typeparam>
  794. /// <param name="collection">元素的集合。</param>
  795. /// <param name="limit">每次遍历的元素数量。</param>
  796. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  797. /// <exception cref="ArgumentOutOfRangeException" />
  798. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Func<T[], int, JumpStatement> callback)
  799. {
  800. if (limit < 1) throw new ArgumentOutOfRangeException(nameof(limit));
  801. if (collection == null) return;
  802. if (callback == null) return;
  803. if (collection is T[] array)
  804. {
  805. var total = array.LongLength;
  806. var start = 0L;
  807. var index = 0;
  808. var length = 0L;
  809. while (start < total)
  810. {
  811. length = limit;
  812. if (start + length > total) length = total - start;
  813. var temp = new T[length];
  814. System.Array.Copy(array, start, temp, 0L, length);
  815. var jump = callback.Invoke(temp, index);
  816. if (jump == JumpStatement.Break) break;
  817. start += length;
  818. index += 1;
  819. }
  820. return;
  821. }
  822. else
  823. {
  824. var queue = new Queue<T>(collection);
  825. var index = 0;
  826. while (queue.Count > 0)
  827. {
  828. var list = new List<T>(limit);
  829. while (list.Count < limit && queue.Count > 0) list.Add(queue.Dequeue());
  830. var temp = list.ToArray();
  831. var jump = callback.Invoke(temp, index);
  832. if (jump == JumpStatement.Break) break;
  833. index += 1;
  834. }
  835. }
  836. }
  837. #endregion
  838. #region Join
  839. /// <summary>连接多个集合的元素为单个集合。</summary>
  840. public static T[] Join<T>(params IEnumerable<T>[] collections)
  841. {
  842. if (collections == null) return new T[0];
  843. var count = collections.Length;
  844. if (count < 1) return new T[0];
  845. var result = new List<T>();
  846. foreach (var collection in collections)
  847. {
  848. if (collection == null) continue;
  849. foreach (var item in collection)
  850. {
  851. result.Add(item);
  852. }
  853. }
  854. return result.ToArray();
  855. }
  856. #endregion
  857. }
  858. }