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.

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