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.

313 lines
10 KiB

4 years ago
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. namespace Apewer.Internals
  6. {
  7. internal class CollectionHelper
  8. {
  9. #region 排序。
  10. public static List<T> Sort<T>(List<T> list, Func<T, T, int> comparison)
  11. {
  12. if (list == null) return null;
  13. if (comparison == null) return list;
  14. list.Sort(new Comparison<T>(comparison));
  15. return list;
  16. }
  17. public static List<T> Ascend<T>(List<T> list) where T : IComparable<T>
  18. {
  19. if (list == null) return null;
  20. list.Sort((a, b) => a.CompareTo(b));
  21. return list;
  22. }
  23. public static List<T> Descend<T>(List<T> list) where T : IComparable<T>
  24. {
  25. if (list == null) return null;
  26. list.Sort((a, b) => -a.CompareTo(b));
  27. return list;
  28. }
  29. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TKey, TKey, int> comparison)
  30. {
  31. if (dict == null) return null;
  32. if (comparison == null) return null;
  33. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  34. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Key, b.Key)));
  35. dict.Clear();
  36. foreach (var item in list) dict.Add(item.Key, item.Value);
  37. return dict;
  38. }
  39. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TValue, TValue, int> comparison)
  40. {
  41. if (dict == null) return null;
  42. if (comparison == null) return dict;
  43. var list = new List<KeyValuePair<TKey, TValue>>(dict);
  44. list.Sort(new Comparison<KeyValuePair<TKey, TValue>>((a, b) => comparison(a.Value, b.Value)));
  45. dict.Clear();
  46. foreach (var item in list) dict.Add(item.Key, item.Value);
  47. return dict;
  48. }
  49. #endregion
  50. public static T First<T>(IEnumerable<T> collection, T failed = default(T))
  51. {
  52. if (collection == null) return failed;
  53. var array = collection as T[];
  54. if (array != null) return array.Length > 0 ? array[0] : failed;
  55. var list = collection as IList<T>;
  56. if (list != null) return list.Count > 0 ? list[0] : failed;
  57. foreach (var item in collection) return item;
  58. return failed;
  59. }
  60. public static T Last<T>(IEnumerable<T> collection, T failed = default(T))
  61. {
  62. if (collection == null) return failed;
  63. var array = collection as T[];
  64. if (array != null) return array.Length > 0 ? array[array.Length - 1] : failed;
  65. var list = collection as IList<T>;
  66. if (list != null) return list.Count > 0 ? list[list.Count - 1] : failed;
  67. var value = failed;
  68. foreach (var item in collection) value = item;
  69. return value;
  70. }
  71. // 安全转换为 List<T> 对象。可指定排除 NULL 值元素。
  72. public static List<T> ToList<T>(IEnumerable<T> objects, bool excludeNull = false)
  73. {
  74. if (objects == null) return new List<T>();
  75. var list = new List<T>();
  76. var collection = objects as ICollection;
  77. if (collection != null)
  78. {
  79. list.AddRange(objects);
  80. }
  81. else
  82. {
  83. var group = 1024;
  84. var added = 0;
  85. var capacity = 0;
  86. if (objects != null)
  87. {
  88. foreach (var item in objects)
  89. {
  90. if (excludeNull && item == null) continue;
  91. if (added == capacity)
  92. {
  93. capacity += group;
  94. list.Capacity = capacity;
  95. }
  96. list.Add(item);
  97. added += 1;
  98. }
  99. }
  100. list.Capacity = added;
  101. }
  102. return list;
  103. }
  104. // 安全转换为 T[] 对象。可指定排除 NULL 值元素。
  105. public static T[] ToArray<T>(IEnumerable<T> objects, bool excludeNull = false)
  106. {
  107. if (objects == null) return new T[0];
  108. if (objects is T[]) return (T[])objects;
  109. var collection = objects as ICollection;
  110. if (collection != null)
  111. {
  112. var array = new T[collection.Count];
  113. collection.CopyTo(array, 0);
  114. return array;
  115. }
  116. else
  117. {
  118. var group = 1024;
  119. var array = new T[group];
  120. var added = 0;
  121. var capacity = 0;
  122. foreach (var item in objects)
  123. {
  124. if (excludeNull && item == null) continue;
  125. if (added == capacity)
  126. {
  127. capacity += group;
  128. var temp = new T[capacity];
  129. Array.Copy(array, 0, temp, 0, added);
  130. array = temp;
  131. }
  132. array[added] = item;
  133. added += 1;
  134. }
  135. if (added < 1 || added == capacity) return array;
  136. var collapsed = new T[added];
  137. Array.Copy(array, 0, collapsed, 0, added);
  138. return collapsed;
  139. }
  140. }
  141. public static bool IsEmpty<T>(IEnumerable<T> objects)
  142. {
  143. if (objects == null) return true;
  144. if (objects is T[]) return ((T[])objects).LongLength == 0;
  145. if (objects is ICollection<T>) return ((ICollection<T>)objects).Count == 0;
  146. foreach (var i in objects) return false;
  147. return true;
  148. }
  149. public static bool NotEmpty<T>(IEnumerable<T> objects) => !IsEmpty<T>(objects);
  150. // 判断集合包含特定值。
  151. public static bool Contains<T>(IEnumerable<T> objects, T cell)
  152. {
  153. if (objects == null) return false;
  154. // objects 实现了含有 Contains 方法的接口。
  155. if (objects is ICollection<T>) return ((ICollection<T>)objects).Contains(cell);
  156. // cell 无效。
  157. if (cell == null)
  158. {
  159. foreach (var i in objects)
  160. {
  161. if (i == null) return true;
  162. }
  163. return false;
  164. }
  165. // cell 有效,进行默认比较。
  166. var comparer = EqualityComparer<T>.Default;
  167. foreach (var i in objects)
  168. {
  169. if (comparer.Equals(i, cell)) return true;
  170. }
  171. return false;
  172. }
  173. // 获取集合中元素的数量。
  174. public static int Count<T>(IEnumerable<T> objects)
  175. {
  176. if (objects == null) return 0;
  177. var array = objects as T[];
  178. if (array != null) return array.Length;
  179. var collection = objects as ICollection<T>;
  180. if (collection != null) return collection.Count;
  181. var count = 0;
  182. foreach (var cell in objects) count++;
  183. return count;
  184. }
  185. // 对元素去重,且去除 NULL 值。
  186. public static T[] Distinct<T>(IEnumerable<T> items)
  187. {
  188. if (items == null) throw new ArgumentNullException(nameof(items));
  189. var count = Count(items);
  190. var added = 0;
  191. var array = new T[count];
  192. var comparer = EqualityComparer<T>.Default;
  193. foreach (var item in items)
  194. {
  195. if (item == null) continue;
  196. var contains = false;
  197. foreach (var i in array)
  198. {
  199. if (comparer.Equals(i, item))
  200. {
  201. contains = true;
  202. break;
  203. }
  204. }
  205. if (contains) continue;
  206. array[added] = item;
  207. added++;
  208. }
  209. if (added < count)
  210. {
  211. var temp = new T[added];
  212. Array.Copy(array, 0, temp, 0, added);
  213. array = temp;
  214. }
  215. return array;
  216. }
  217. // 获取可枚举集合的部分元素。
  218. public static T[] Slice<T>(IEnumerable<T> objects, int skip = 0, int count = -1, Func<T> stuffer = null)
  219. {
  220. if (count == 0) return new T[0];
  221. var ab = new ArrayBuilder<T>();
  222. var added = 0;
  223. if (skip < 0)
  224. {
  225. var end = 0 - skip;
  226. for (var i = 0; i < end; i++)
  227. {
  228. ab.Add(stuffer == null ? default : stuffer());
  229. added++;
  230. if (count > 0 && added == count) return ab.Export();
  231. }
  232. }
  233. if (objects != null)
  234. {
  235. var offset = 0;
  236. foreach (var item in objects)
  237. {
  238. if (offset < skip)
  239. {
  240. offset++;
  241. continue;
  242. }
  243. ab.Add(item);
  244. added++;
  245. offset++;
  246. if (count > 0 && added == count) return ab.Export();
  247. }
  248. }
  249. while (added < count)
  250. {
  251. ab.Add(stuffer == null ? default : stuffer());
  252. added++;
  253. }
  254. return ab.Export();
  255. }
  256. public static IList<T> Add<T>(IList<T> list, IEnumerable<T> items)
  257. {
  258. if (list != null && items != null)
  259. {
  260. foreach (var item in items) list.Add(item);
  261. }
  262. return list;
  263. }
  264. public static bool Add<TKey, TValue>(IList<KeyValuePair<TKey, TValue>> list, TKey key, TValue value)
  265. {
  266. if (list == null) return false;
  267. list.Add(new KeyValuePair<TKey, TValue>(key, value));
  268. return true;
  269. }
  270. }
  271. }