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.

1100 lines
40 KiB

5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
1 year ago
5 years ago
1 year ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
2 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
2 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
2 years ago
2 years ago
3 years ago
2 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
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
5 years ago
  1. using Newtonsoft.Json.Linq;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Collections.Specialized;
  6. using System.Text;
  7. namespace Apewer
  8. {
  9. /// <summary>集合的实用工具。</summary>
  10. public static class CollectionUtility
  11. {
  12. #region 判断
  13. /// <summary>判断集合为空。</summary>
  14. public static bool IsEmpty<T>(IEnumerable<T> objects)
  15. {
  16. if (objects == null) return true;
  17. if (objects is T[]) return ((T[])objects).LongLength < 1L;
  18. if (objects is ICollection<T>) return ((ICollection<T>)objects).Count < 1;
  19. foreach (var item in objects) return false;
  20. return true;
  21. }
  22. /// <summary>判断集合存在元素。</summary>
  23. public static bool NotEmpty<T>(IEnumerable<T> objects)
  24. {
  25. if (objects == null) return false;
  26. if (objects is T[]) return ((T[])objects).LongLength > 0L;
  27. if (objects is ICollection<T>) return ((ICollection<T>)objects).Count > 0;
  28. foreach (var item in objects) return true;
  29. return false;
  30. }
  31. /// <summary>获取集合中元素的数量。</summary>
  32. public static int Count<T>(IEnumerable<T> objects)
  33. {
  34. if (objects == null) return 0;
  35. var array = objects as T[];
  36. if (array != null) return array.Length;
  37. var collection = objects as ICollection<T>;
  38. if (collection != null) return collection.Count;
  39. var count = 0;
  40. foreach (var cell in objects) count++;
  41. return count;
  42. }
  43. /// <summary>检查集合是否包含 item。</summary>
  44. public static bool Contains<T>(IEnumerable<T> objects, T cell)
  45. {
  46. if (objects == null) return false;
  47. // objects 实现了含有 Contains 方法的接口。
  48. if (objects is ICollection<T>) return ((ICollection<T>)objects).Contains(cell);
  49. // cell 无效。
  50. if (cell == null)
  51. {
  52. foreach (var i in objects)
  53. {
  54. if (i == null) return true;
  55. }
  56. return false;
  57. }
  58. // cell 有效,进行默认比较。
  59. var comparer = EqualityComparer<T>.Default;
  60. foreach (var i in objects)
  61. {
  62. if (comparer.Equals(i, cell)) return true;
  63. }
  64. return false;
  65. }
  66. /// <summary>获取 item 在集合中的偏移位置,不存在时返回 -1。</summary>
  67. public static int IndexOf<T>(IEnumerable<T> objects, T item)
  68. {
  69. if (objects == null) return -1;
  70. if (objects is IList list) return list.IndexOf(item);
  71. if (item == null)
  72. {
  73. if (objects is T[] array)
  74. {
  75. var length = array.Length;
  76. for (var i = 0; i < length; i++)
  77. {
  78. if (array[i] == null) return i;
  79. }
  80. return -1;
  81. }
  82. var index = 0;
  83. foreach (var obj in objects)
  84. {
  85. if (obj == null) return index;
  86. index++;
  87. }
  88. return -1;
  89. }
  90. else
  91. {
  92. var comparer = EqualityComparer<T>.Default;
  93. if (objects is T[] array)
  94. {
  95. var length = array.Length;
  96. for (var i = 0; i < length; i++)
  97. {
  98. if (comparer.Equals(item, array[i])) return i;
  99. }
  100. return -1;
  101. }
  102. var index = 0;
  103. foreach (var obj in objects)
  104. {
  105. if (comparer.Equals(item, obj)) return index;
  106. index++;
  107. }
  108. return -1;
  109. }
  110. }
  111. #endregion
  112. #region 类型转换
  113. /// <summary>转换模型类型。</summary>
  114. public static TDst[] As<TSrc, TDst>(this TSrc[] array) where TDst : class
  115. {
  116. if (array == null) return null;
  117. var count = array.Length;
  118. var output = new TDst[count];
  119. for (var i = 0; i < count; i++)
  120. {
  121. var item = array[i];
  122. if (item == null) continue;
  123. output[i] = item as TDst;
  124. }
  125. return output;
  126. }
  127. /// <summary>转换模型类型。</summary>
  128. public static TDst[] As<TSrc, TDst>(this TSrc[] array, Func<TSrc, TDst> convert)
  129. {
  130. if (convert == null) throw new ArgumentNullException(nameof(convert));
  131. if (array == null) return null;
  132. var count = array.Length;
  133. var output = new TDst[count];
  134. for (var i = 0; i < count; i++)
  135. {
  136. var item = array[i];
  137. if (item == null) continue;
  138. output[i] = convert(item);
  139. }
  140. return output;
  141. }
  142. /// <summary>安全转换为 List&lt;<typeparamref name="T"/>&gt; 对象。可指定排除 NULL 值元素。</summary>
  143. public static List<T> List<T>(IEnumerable<T> objects, bool excludeNull = false)
  144. {
  145. if (objects == null) return new List<T>();
  146. var list = new List<T>();
  147. var collection = objects as ICollection;
  148. if (collection != null)
  149. {
  150. list.AddRange(objects);
  151. }
  152. else
  153. {
  154. var group = 1024;
  155. var added = 0;
  156. var capacity = 0;
  157. if (objects != null)
  158. {
  159. foreach (var item in objects)
  160. {
  161. if (excludeNull && item == null) continue;
  162. if (added == capacity)
  163. {
  164. capacity += group;
  165. list.Capacity = capacity;
  166. }
  167. list.Add(item);
  168. added += 1;
  169. }
  170. }
  171. list.Capacity = added;
  172. }
  173. return list;
  174. }
  175. /// <summary>安全转换为 &lt;<typeparamref name="T"/>&gt;[] 对象。可指定排除 NULL 值元素。</summary>
  176. public static T[] Array<T>(IEnumerable<T> objects, bool excludeNull = false)
  177. {
  178. if (objects == null) return new T[0];
  179. if (objects is T[]) return (T[])objects;
  180. var collection = objects as ICollection;
  181. if (collection != null)
  182. {
  183. var array = new T[collection.Count];
  184. collection.CopyTo(array, 0);
  185. return array;
  186. }
  187. else
  188. {
  189. var group = 1024;
  190. var array = new T[group];
  191. var added = 0;
  192. var capacity = 0;
  193. foreach (var item in objects)
  194. {
  195. if (excludeNull && item == null) continue;
  196. if (added == capacity)
  197. {
  198. capacity += group;
  199. var temp = new T[capacity];
  200. System.Array.Copy(array, 0, temp, 0, added);
  201. array = temp;
  202. }
  203. array[added] = item;
  204. added += 1;
  205. }
  206. if (added < 1 || added == capacity) return array;
  207. var collapsed = new T[added];
  208. System.Array.Copy(array, 0, collapsed, 0, added);
  209. return collapsed;
  210. }
  211. }
  212. /// <summary>生成 StringPairs 对象实例为副本。</summary>
  213. public static StringPairs StringPairs(NameValueCollection @this) => Apewer.StringPairs.From(@this);
  214. /// <summary>转换集合为数组。</summary>
  215. /// <param name="collection"></param>
  216. /// <returns></returns>
  217. public static Dictionary<string, string[]> Dictionary(NameValueCollection collection)
  218. {
  219. if (collection == null) return null;
  220. var count = collection.Count;
  221. var dict = new Dictionary<string, string[]>();
  222. for (var i = 0; i < count; i++)
  223. {
  224. var key = collection.GetKey(i);
  225. var values = collection.GetValues(i);
  226. dict.Add(key, values);
  227. }
  228. return dict;
  229. }
  230. /// <summary>转换集合为字典。</summary>
  231. /// <typeparam name="TKey">字典 Key 的类型。</typeparam>
  232. /// <typeparam name="TValue">字典 Value 的类型。</typeparam>
  233. /// <param name="items">要转换的集合。</param>
  234. /// <param name="key">根据元素获取 Key 的函数。</param>
  235. /// <exception cref="ArgumentNullException"></exception>
  236. public static Dictionary<TKey, TValue> Dictionary<TKey, TValue>(IEnumerable<TValue> items, Func<TValue, TKey> key)
  237. {
  238. if (items == null) throw new ArgumentNullException(nameof(items));
  239. if (key == null) throw new ArgumentNullException(nameof(key));
  240. var dict = new Dictionary<TKey, TValue>();
  241. foreach (var i in items)
  242. {
  243. if (i == null) continue;
  244. var k = key(i);
  245. if (k.IsNull()) continue;
  246. if (dict.ContainsKey(k)) continue;
  247. dict.Add(k, i);
  248. }
  249. return dict;
  250. }
  251. #endregion
  252. #region 修改集合
  253. /// <summary>添加多个元素。</summary>
  254. public static void Add<T>(List<T> list, params T[] items)
  255. {
  256. if (list != null && items != null) list.AddRange(items);
  257. }
  258. /// <summary>添加多个元素。</summary>
  259. public static IList<T> Add<T>(IList<T> list, IEnumerable<T> items)
  260. {
  261. if (list != null && items != null)
  262. {
  263. foreach (var item in items) list.Add(item);
  264. }
  265. return list;
  266. }
  267. /// <summary>添加元素。</summary>
  268. public static bool Add<TKey, TValue>(IList<KeyValuePair<TKey, TValue>> list, TKey key, TValue value)
  269. {
  270. if (list == null) return false;
  271. list.Add(new KeyValuePair<TKey, TValue>(key, value));
  272. return true;
  273. }
  274. /// <summary>对元素去重,且去除 NULL 值。</summary>
  275. public static T[] Distinct<T>(IEnumerable<T> items)
  276. {
  277. if (items == null) throw new ArgumentNullException(nameof(items));
  278. var count = Count(items);
  279. var added = 0;
  280. var array = new T[count];
  281. var comparer = EqualityComparer<T>.Default;
  282. foreach (var item in items)
  283. {
  284. if (item == null) continue;
  285. var contains = false;
  286. foreach (var i in array)
  287. {
  288. if (comparer.Equals(i, item))
  289. {
  290. contains = true;
  291. break;
  292. }
  293. }
  294. if (contains) continue;
  295. array[added] = item;
  296. added++;
  297. }
  298. if (added < count)
  299. {
  300. var temp = new T[added];
  301. System.Array.Copy(array, 0, temp, 0, added);
  302. array = temp;
  303. }
  304. return array;
  305. }
  306. /// <summary>清理集合,去除 NULL 值。</summary>
  307. public static T[] Vacuum<T>(this IEnumerable<T> items) => FindAll(items, x => x != null);
  308. /// <summary>获取可枚举集合的部分元素。</summary>
  309. /// <typeparam name="T">集合元素的类型。</typeparam>
  310. /// <param name="objects">原集合。</param>
  311. /// <param name="skip">在集合前段要跳过的元素数量。</param>
  312. /// <param name="count">要获取的元素数量,指定为负数时不限元素数量。</param>
  313. /// <param name="stuffer">填充器,获取范围超出原集合的部分,使用此方法填充元素;此函数默认返回 <typeparamref name="T"/> 的默认值。</param>
  314. /// <returns>数量符合 count 的数组。</returns>
  315. public static T[] Slice<T>(IEnumerable<T> objects, int skip = 0, int count = -1, Func<T> stuffer = null)
  316. {
  317. if (count == 0) return new T[0];
  318. var ab = new ArrayBuilder<T>();
  319. var added = 0;
  320. if (skip < 0)
  321. {
  322. var end = 0 - skip;
  323. for (var i = 0; i < end; i++)
  324. {
  325. ab.Add(stuffer == null ? default : stuffer());
  326. added++;
  327. if (count > 0 && added == count) return ab.Export();
  328. }
  329. }
  330. if (objects != null)
  331. {
  332. var offset = 0;
  333. foreach (var item in objects)
  334. {
  335. if (offset < skip)
  336. {
  337. offset++;
  338. continue;
  339. }
  340. ab.Add(item);
  341. added++;
  342. offset++;
  343. if (count > 0 && added == count) return ab.Export();
  344. }
  345. }
  346. while (added < count)
  347. {
  348. ab.Add(stuffer == null ? default : stuffer());
  349. added++;
  350. }
  351. return ab.Export();
  352. }
  353. /// <summary>在数组尾部增加元素,生成新数组,不修改原数组。</summary>
  354. /// <returns>增加元素后的新数组。</returns>
  355. public static T[] Push<T>(this T[] array, T item)
  356. {
  357. if (array == null) return new T[] { item };
  358. var length = array.Length;
  359. var newArray = new T[length + 1];
  360. if (length > 0) System.Array.Copy(array, 0, newArray, 0, length);
  361. newArray[length] = item;
  362. return newArray;
  363. }
  364. /// <summary>在数组尾部增加元素,生成新数组,不修改原数组。</summary>
  365. /// <returns>增加元素后的新数组。</returns>
  366. public static T[] Push<T>(this T[] array, T[] items)
  367. {
  368. if (array == null) return items ?? new T[0];
  369. if (items == null)
  370. {
  371. var result = new T[array.Length];
  372. array.CopyTo(result, 0);
  373. return result;
  374. }
  375. else
  376. {
  377. var length1 = array.Length;
  378. var length2 = items.Length;
  379. var result = new T[length1 + length2];
  380. if (length1 > 0) System.Array.Copy(array, 0, result, 0, length1);
  381. if (length2 > 0) System.Array.Copy(items, 0, result, length1, length2);
  382. return result;
  383. }
  384. }
  385. /// <summary>在数组头部增加元素,生成新数组,不修改原数组。</summary>
  386. /// <returns>增加元素后的新数组。</returns>
  387. public static T[] Unshift<T>(this T[] array, T item)
  388. {
  389. if (array == null) return new T[] { item };
  390. var length = array.Length;
  391. var newArray = new T[length + 1];
  392. newArray[0] = item;
  393. if (length > 0) System.Array.Copy(array, 0, newArray, 1, length);
  394. return newArray;
  395. }
  396. /// <summary>在数组头部增加元素,生成新数组,不修改原数组。</summary>
  397. /// <returns>增加元素后的新数组。</returns>
  398. public static T[] Unshift<T>(this T[] array, T[] items)
  399. {
  400. if (array == null) return items ?? new T[0];
  401. if (items == null)
  402. {
  403. var result = new T[array.Length];
  404. array.CopyTo(result, 0);
  405. return result;
  406. }
  407. else
  408. {
  409. var length1 = array.Length;
  410. var length2 = items.Length;
  411. var result = new T[length1 + length2];
  412. if (length2 > 0) System.Array.Copy(items, 0, result, 0, length2);
  413. if (length1 > 0) System.Array.Copy(array, 0, result, length2, length1);
  414. return result;
  415. }
  416. }
  417. #endregion
  418. #region 排序
  419. /// <summary>对列表中的元素排序。</summary>
  420. /// <returns>返回排序的数组,用于链式写法。</returns>
  421. /// <exception cref="ArgumentNullException"></exception>
  422. public static List<T> Sort<T>(this List<T> list, params Comparison<T>[] comparisons)
  423. {
  424. if (list == null) throw new ArgumentNullException(nameof(list));
  425. if (comparisons == null) throw new ArgumentNullException(nameof(comparisons));
  426. var count = comparisons.Length;
  427. if (count < 1) return list;
  428. for (var i = 0; i < count; i++)
  429. {
  430. if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null.");
  431. }
  432. list.Sort((a, b) =>
  433. {
  434. for (var i = 0; i < count; i++)
  435. {
  436. var compare = comparisons[i].Invoke(a, b);
  437. if (compare != 0) return compare;
  438. }
  439. return Comparer<T>.Default.Compare(a, b);
  440. });
  441. return list;
  442. }
  443. /// <summary>对数组排序。</summary>
  444. /// <returns>返回排序的数组,用于链式写法。</returns>
  445. /// <exception cref="ArgumentNullException" />
  446. /// <exception cref="InvalidOperationException" />
  447. public static T[] Sort<T>(this T[] array)
  448. {
  449. System.Array.Sort(array);
  450. return array;
  451. }
  452. /// <summary>对数组排序。</summary>
  453. /// <returns>返回排序的数组,用于链式写法。</returns>
  454. /// <exception cref="ArgumentNullException"></exception>
  455. /// <exception cref="InvalidOperationException" />
  456. public static T[] Sort<T>(this T[] array, params Comparison<T>[] comparisons)
  457. {
  458. if (array == null) throw new ArgumentNullException(nameof(array));
  459. if (comparisons == null) throw new ArgumentNullException(nameof(comparisons));
  460. var count = comparisons.Length;
  461. if (count < 1) return array;
  462. for (var i = 0; i < count; i++)
  463. {
  464. if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null.");
  465. }
  466. System.Array.Sort(array, (a, b) =>
  467. {
  468. for (var i = 0; i < count; i++)
  469. {
  470. var compare = comparisons[i].Invoke(a, b);
  471. if (compare != 0) return compare;
  472. }
  473. return Comparer<T>.Default.Compare(a, b);
  474. });
  475. return array;
  476. }
  477. /// <summary>获取集合中的第一个元素。可指定失败时的默认返回值。</summary>
  478. public static T First<T>(IEnumerable<T> collection, T failed = default(T))
  479. {
  480. if (collection == null) return failed;
  481. var array = collection as T[];
  482. if (array != null) return array.Length > 0 ? array[0] : failed;
  483. var list = collection as IList<T>;
  484. if (list != null) return list.Count > 0 ? list[0] : failed;
  485. foreach (var item in collection) return item;
  486. return failed;
  487. }
  488. /// <summary>获取集合中的最后一个元素。可指定失败时的默认返回值。</summary>
  489. public static T Last<T>(IEnumerable<T> collection, T failed = default(T))
  490. {
  491. if (collection == null) return failed;
  492. var array = collection as T[];
  493. if (array != null) return array.Length > 0 ? array[array.Length - 1] : failed;
  494. var list = collection as IList<T>;
  495. if (list != null) return list.Count > 0 ? list[list.Count - 1] : failed;
  496. var value = failed;
  497. foreach (var item in collection) value = item;
  498. return value;
  499. }
  500. /// <summary>对数组升序排序。</summary>
  501. /// <exception cref="NullReferenceException"></exception>
  502. public static T[] Ascend<T>(T[] array) where T : IComparable<T>
  503. {
  504. if (array == null) return null;
  505. array.Sort((a, b) => a.CompareTo(b));
  506. return array;
  507. }
  508. /// <summary>对数组升序排序。</summary>
  509. /// <exception cref="NullReferenceException"></exception>
  510. public static List<T> Ascend<T>(List<T> list) where T : IComparable<T>
  511. {
  512. if (list == null) return null;
  513. list.Sort((a, b) => a.CompareTo(b));
  514. return list;
  515. }
  516. /// <summary>对数组升序排序。</summary>
  517. /// <exception cref="NullReferenceException"></exception>
  518. public static void Ascend<T, TProp>(T[] array, Func<T, TProp> func) where TProp : IComparable<TProp>
  519. {
  520. if (array != null && func != null) Sort(array, (a, b) => func(a).CompareTo(func(b)));
  521. }
  522. /// <summary>对数组降序排序。</summary>
  523. /// <exception cref="NullReferenceException"></exception>
  524. public static T[] Descend<T>(T[] array) where T : IComparable<T>
  525. {
  526. if (array == null) return array;
  527. Sort(array, (a, b) => 0 - a.CompareTo(b));
  528. return array;
  529. }
  530. /// <summary>对数组降序排序。</summary>
  531. /// <exception cref="NullReferenceException"></exception>
  532. public static List<T> Descend<T>(List<T> list) where T : IComparable<T>
  533. {
  534. if (list == null) return null;
  535. list.Sort((a, b) => -a.CompareTo(b));
  536. return list;
  537. }
  538. /// <summary>对数组降序排序。</summary>
  539. /// <exception cref="NullReferenceException"></exception>
  540. public static void Descend<T, TProp>(T[] array, Func<T, TProp> func) where TProp : IComparable<TProp>
  541. {
  542. if (array != null && func != null) Sort(array, (a, b) => 0 - func(a).CompareTo(func(b)));
  543. }
  544. /// <summary>对字典中的键排序。</summary>
  545. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TKey, TKey, int> comparison)
  546. {
  547. if (dict == null) return null;
  548. if (comparison == null) return null;
  549. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  550. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Key, b.Key)));
  551. dict.Clear();
  552. foreach (var item in list) dict.Add(item.Key, item.Value);
  553. return dict;
  554. }
  555. /// <summary>对字典中的键排序。</summary>
  556. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> @this) where TKey : IComparable<TKey>
  557. {
  558. return SortKey(@this, (a, b) => a.CompareTo(b));
  559. }
  560. /// <summary>对字典中的值排序。</summary>
  561. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TValue, TValue, int> comparison)
  562. {
  563. if (dict == null) return null;
  564. if (comparison == null) return dict;
  565. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  566. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Value, b.Value)));
  567. dict.Clear();
  568. foreach (var item in list) dict.Add(item.Key, item.Value);
  569. return dict;
  570. }
  571. /// <summary>对字典中的值排序。</summary>
  572. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> @this) where TValue : IComparable<TValue>
  573. {
  574. return SortValue(@this, (a, b) => a.CompareTo(b));
  575. }
  576. #endregion
  577. #region params
  578. internal static object[] ParseParams(object cells)
  579. {
  580. var parsed = new ArrayBuilder<object>();
  581. ParseParams(cells, parsed, 1);
  582. return parsed;
  583. }
  584. static void ParseParams(object cells, ArrayBuilder<object> parsed, int depth)
  585. {
  586. if (cells.IsNull()) return;
  587. if (cells is string str)
  588. {
  589. parsed.Add(cells);
  590. return;
  591. }
  592. if (cells is IList items)
  593. {
  594. if (depth > 64)
  595. {
  596. parsed.Add(nameof(IList));
  597. return;
  598. }
  599. var count = items.Count;
  600. for (var i = 0; i < count; i++)
  601. {
  602. ParseParams(items[i], parsed, depth + 1);
  603. }
  604. return;
  605. }
  606. parsed.Add(cells.ToString());
  607. }
  608. #endregion
  609. #region Find
  610. /// <summary>根据条件筛选,将符合条件的元素组成新数组。</summary>
  611. public static T[] FindAll<T>(this IEnumerable<T> collection, Predicate<T> match)
  612. {
  613. if (collection == null) throw new ArgumentNullException(nameof(collection));
  614. if (match == null) throw new ArgumentNullException(nameof(match));
  615. if (collection is T[] array)
  616. {
  617. return System.Array.FindAll<T>(array, match);
  618. }
  619. else if (collection is IList<T> list)
  620. {
  621. var count = list.Count;
  622. var result = new List<T>(count);
  623. for (var i = 0; i < count; i++)
  624. {
  625. var matched = match.Invoke(list[i]);
  626. if (matched) result.Add(list[i]);
  627. }
  628. return result.ToArray();
  629. }
  630. else
  631. {
  632. var result = new List<T>();
  633. foreach (var item in collection)
  634. {
  635. var matched = match.Invoke(item);
  636. if (matched) result.Add(item);
  637. }
  638. return result.ToArray();
  639. }
  640. }
  641. /// <summary>根据条件筛选,找到第一个符合条件的元素。</summary>
  642. public static T Find<T>(this IEnumerable<T> collection, Predicate<T> match)
  643. {
  644. if (collection == null) throw new ArgumentNullException(nameof(collection));
  645. if (match == null) throw new ArgumentNullException(nameof(match));
  646. if (collection is T[] array)
  647. {
  648. return System.Array.Find<T>(array, match);
  649. }
  650. else if (collection is IList<T> list)
  651. {
  652. var count = list.Count;
  653. for (var i = 0; i < count; i++)
  654. {
  655. var matched = match.Invoke(list[i]);
  656. if (matched) return list[i];
  657. }
  658. }
  659. else
  660. {
  661. foreach (var item in collection)
  662. {
  663. var matched = match.Invoke(item);
  664. if (matched) return item;
  665. }
  666. }
  667. return default;
  668. }
  669. #endregion
  670. #region Map
  671. /// <summary>遍历集合,转换元素,生成新数组。</summary>
  672. /// <typeparam name="TIn">输入的元素类型。</typeparam>
  673. /// <typeparam name="TOut">输出的元素类型。</typeparam>
  674. /// <param name="collection">要遍历的集合。</param>
  675. /// <param name="selector">转换程序。</param>
  676. /// <returns>新数组的元素类型。</returns>
  677. public static TOut[] Map<TIn, TOut>(this IEnumerable<TIn> collection, Func<TIn, TOut> selector)
  678. {
  679. if (selector == null) throw new ArgumentNullException(nameof(selector));
  680. if (collection == null) return new TOut[0];
  681. return Map(collection, (item, index) => selector.Invoke(item));
  682. }
  683. /// <summary>遍历集合,转换元素,生成新数组。</summary>
  684. /// <typeparam name="TIn">输入的元素类型。</typeparam>
  685. /// <typeparam name="TOut">输出的元素类型。</typeparam>
  686. /// <param name="collection">要遍历的集合。</param>
  687. /// <param name="selector">转换程序,提供索引参数(从 0 开始)。</param>
  688. /// <returns>新数组的元素类型。</returns>
  689. public static TOut[] Map<TIn, TOut>(this IEnumerable<TIn> collection, Func<TIn, int, TOut> selector)
  690. {
  691. if (selector == null) throw new ArgumentNullException(nameof(selector));
  692. if (collection == null) return new TOut[0];
  693. if (collection is TIn[] array)
  694. {
  695. var count = array.Length;
  696. var result = new TOut[count];
  697. for (var i = 0; i < count; i++)
  698. {
  699. result[i] = selector.Invoke(array[i], i);
  700. }
  701. return result;
  702. }
  703. else
  704. {
  705. var capacity = 0;
  706. var count = 0;
  707. var list = new List<TOut>();
  708. foreach (var item in collection)
  709. {
  710. if (capacity == count)
  711. {
  712. capacity += 1024;
  713. list.Capacity = capacity;
  714. }
  715. list.Add(selector.Invoke(item, count));
  716. count += 1;
  717. }
  718. return list.ToArray();
  719. }
  720. }
  721. #endregion
  722. #region ForEach
  723. /// <summary>遍历每个元素,执行回调。</summary>
  724. /// <typeparam name="T">元素的类型。</typeparam>
  725. /// <param name="collection">元素的集合。</param>
  726. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  727. public static void ForEach<T>(this IEnumerable<T> collection, Action<T> callback)
  728. {
  729. if (collection == null || callback == null) return;
  730. ForEach<T>(collection, (item, index) =>
  731. {
  732. callback.Invoke(item);
  733. return JumpStatement.Continue;
  734. });
  735. }
  736. /// <summary>遍历每个元素,执行回调。</summary>
  737. /// <typeparam name="T">元素的类型。</typeparam>
  738. /// <param name="collection">元素的集合。</param>
  739. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  740. public static void ForEach<T>(this IEnumerable<T> collection, Action<T, int> callback)
  741. {
  742. if (collection == null || callback == null) return;
  743. ForEach<T>(collection, (item, index) =>
  744. {
  745. callback.Invoke(item, index);
  746. return JumpStatement.Continue;
  747. });
  748. }
  749. /// <summary>遍历每个元素,执行回调。</summary>
  750. /// <typeparam name="T">元素的类型。</typeparam>
  751. /// <param name="collection">元素的集合。</param>
  752. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  753. public static void ForEach<T>(this IEnumerable<T> collection, Func<T, JumpStatement> callback)
  754. {
  755. if (collection == null || callback == null) return;
  756. ForEach<T>(collection, (item, index) =>
  757. {
  758. var result = callback.Invoke(item);
  759. return result;
  760. });
  761. }
  762. /// <summary>遍历每个元素,执行回调。</summary>
  763. /// <typeparam name="T">元素的类型。</typeparam>
  764. /// <param name="collection">元素的集合。</param>
  765. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。返回 true 将继续遍历,返回 false 打断遍历。</param>
  766. public static void ForEach<T>(this IEnumerable<T> collection, Func<T, int, JumpStatement> callback)
  767. {
  768. if (collection == null || callback == null) return;
  769. if (collection is T[] array)
  770. {
  771. var count = array.Length;
  772. for (var i = 0; i < count; i++)
  773. {
  774. var jump = callback.Invoke(array[i], i);
  775. if (jump == JumpStatement.Break) break;
  776. }
  777. }
  778. else
  779. {
  780. var index = 0;
  781. foreach (var item in collection)
  782. {
  783. var jump = callback.Invoke(item, index);
  784. if (jump == JumpStatement.Break) break;
  785. index += 1;
  786. }
  787. }
  788. }
  789. /// <summary>遍历每个元素,执行回调。</summary>
  790. /// <typeparam name="T">元素的类型。</typeparam>
  791. /// <param name="collection">元素的集合。</param>
  792. /// <param name="limit">每次遍历的元素数量。</param>
  793. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  794. /// <exception cref="ArgumentOutOfRangeException" />
  795. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Action<T[]> callback)
  796. {
  797. if (collection == null || callback == null) return;
  798. ForEach<T>(collection, limit, (items, index) =>
  799. {
  800. callback.Invoke(items);
  801. return JumpStatement.Continue;
  802. });
  803. }
  804. /// <summary>遍历每个元素,执行回调。</summary>
  805. /// <typeparam name="T">元素的类型。</typeparam>
  806. /// <param name="collection">元素的集合。</param>
  807. /// <param name="limit">每次遍历的元素数量。</param>
  808. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  809. /// <exception cref="ArgumentOutOfRangeException" />
  810. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Action<T[], int> callback)
  811. {
  812. if (collection == null || callback == null) return;
  813. ForEach<T>(collection, limit, (items, index) =>
  814. {
  815. callback.Invoke(items, index);
  816. return JumpStatement.Continue;
  817. });
  818. }
  819. /// <summary>遍历每个元素,执行回调。</summary>
  820. /// <typeparam name="T">元素的类型。</typeparam>
  821. /// <param name="collection">元素的集合。</param>
  822. /// <param name="limit">每次遍历的元素数量。</param>
  823. /// <param name="callback">回调。参数为本次遍历的元素。</param>
  824. /// <exception cref="ArgumentOutOfRangeException" />
  825. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Func<T[], JumpStatement> callback)
  826. {
  827. if (collection == null || callback == null) return;
  828. ForEach<T>(collection, limit, (items, index) =>
  829. {
  830. var result = callback.Invoke(items);
  831. return result;
  832. });
  833. }
  834. /// <summary>遍历每个元素,执行回调。</summary>
  835. /// <typeparam name="T">元素的类型。</typeparam>
  836. /// <param name="collection">元素的集合。</param>
  837. /// <param name="limit">每次遍历的元素数量。</param>
  838. /// <param name="callback">回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。</param>
  839. /// <exception cref="ArgumentOutOfRangeException" />
  840. public static void ForEach<T>(this IEnumerable<T> collection, int limit, Func<T[], int, JumpStatement> callback)
  841. {
  842. if (limit < 1) throw new ArgumentOutOfRangeException(nameof(limit));
  843. if (collection == null) return;
  844. if (callback == null) return;
  845. if (collection is T[] array)
  846. {
  847. var total = array.LongLength;
  848. var start = 0L;
  849. var index = 0;
  850. var length = 0L;
  851. while (start < total)
  852. {
  853. length = limit;
  854. if (start + length > total) length = total - start;
  855. var temp = new T[length];
  856. System.Array.Copy(array, start, temp, 0L, length);
  857. var jump = callback.Invoke(temp, index);
  858. if (jump == JumpStatement.Break) break;
  859. start += length;
  860. index += 1;
  861. }
  862. return;
  863. }
  864. else
  865. {
  866. var queue = new Queue<T>(collection);
  867. var index = 0;
  868. while (queue.Count > 0)
  869. {
  870. var list = new List<T>(limit);
  871. while (list.Count < limit && queue.Count > 0) list.Add(queue.Dequeue());
  872. var temp = list.ToArray();
  873. var jump = callback.Invoke(temp, index);
  874. if (jump == JumpStatement.Break) break;
  875. index += 1;
  876. }
  877. }
  878. }
  879. #endregion
  880. #region Join
  881. /// <summary>连接多个集合的元素为单个集合。</summary>
  882. public static T[] Join<T>(params IEnumerable<T>[] collections)
  883. {
  884. if (collections == null) return new T[0];
  885. var count = collections.Length;
  886. if (count < 1) return new T[0];
  887. var result = new List<T>();
  888. foreach (var collection in collections)
  889. {
  890. if (collection == null) continue;
  891. foreach (var item in collection)
  892. {
  893. result.Add(item);
  894. }
  895. }
  896. return result.ToArray();
  897. }
  898. #endregion
  899. #region With
  900. /// <summary>Array 实例的 with() 方法是使用方括号表示法修改指定索引值的复制方法版本。它会返回一个新数组,其指定索引处的值会被新值替换。</summary>
  901. /// <param name="array"></param>
  902. /// <param name="index">要修改的数组索引(从 0 开始)。负数索引会从数组末尾开始计数——即当 index &lt; 0 时,会使用 index + array.length。</param>
  903. /// <param name="value">要分配给指定索引的任何值。</param>
  904. /// <returns>一个全新的数组,其中 index 索引处的元素被替换为 value。</returns>
  905. /// <exception cref="ArgumentNullException" />
  906. public static T[] With<T>(this T[] array, int index, T value)
  907. {
  908. if (array == null) throw new ArgumentNullException(nameof(array));
  909. // 数组长度
  910. var length = array.Length;
  911. if (array.Length < 1) throw new ArgumentOutOfRangeException(nameof(index));
  912. // 要修改的位置
  913. var offset = index < 0 ? index + length : index;
  914. if (offset >= length || offset < 0) throw new ArgumentOutOfRangeException(nameof(index));
  915. // 生成新数组
  916. var result = new T[array.Length];
  917. for (var i = 0; i < result.Length; i++) result[i] = array[i];
  918. result[offset] = value;
  919. return result;
  920. }
  921. #endregion
  922. #region Group
  923. /// <summary>对元素按指定的键分组。</summary>
  924. /// <param name="items"></param>
  925. /// <param name="keyGetter"></param>
  926. public static Dictionary<TKey, TValue[]> Group<TKey, TValue>(this IEnumerable<TValue> items, Func<TValue, TKey> keyGetter)
  927. {
  928. if (items == null) throw new ArgumentNullException(nameof(items));
  929. if (keyGetter == null) throw new ArgumentNullException(nameof(keyGetter));
  930. var dict = new SortedDictionary<TKey, List<TValue>>();
  931. foreach (var item in items)
  932. {
  933. var key = keyGetter.Invoke(item);
  934. if (key.IsNull()) continue;
  935. if (dict.TryGetValue(key, out var list))
  936. {
  937. list.Add(item);
  938. }
  939. else
  940. {
  941. list = new List<TValue>();
  942. list.Add(item);
  943. dict.Add(key, list);
  944. }
  945. }
  946. var result = new Dictionary<TKey, TValue[]>(dict.Count);
  947. foreach (var kvp in dict)
  948. {
  949. result.Add(kvp.Key, kvp.Value.ToArray());
  950. }
  951. return result;
  952. }
  953. #endregion
  954. }
  955. }