using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Text; namespace Apewer { /// 集合的实用工具。 public static class CollectionUtility { #region 判断 /// 判断集合为空。 public static bool IsEmpty(IEnumerable objects) { if (objects == null) return true; if (objects is T[]) return ((T[])objects).LongLength < 1L; if (objects is ICollection) return ((ICollection)objects).Count < 1; foreach (var item in objects) return false; return true; } /// 判断集合存在元素。 public static bool NotEmpty(IEnumerable objects) { if (objects == null) return false; if (objects is T[]) return ((T[])objects).LongLength > 0L; if (objects is ICollection) return ((ICollection)objects).Count > 0; foreach (var item in objects) return true; return false; } /// 获取集合中元素的数量。 public static int Count(IEnumerable objects) { if (objects == null) return 0; var array = objects as T[]; if (array != null) return array.Length; var collection = objects as ICollection; if (collection != null) return collection.Count; var count = 0; foreach (var cell in objects) count++; return count; } /// 检查集合是否包含 item。 public static bool Contains(IEnumerable objects, T cell) { if (objects == null) return false; // objects 实现了含有 Contains 方法的接口。 if (objects is ICollection) return ((ICollection)objects).Contains(cell); // cell 无效。 if (cell == null) { foreach (var i in objects) { if (i == null) return true; } return false; } // cell 有效,进行默认比较。 var comparer = EqualityComparer.Default; foreach (var i in objects) { if (comparer.Equals(i, cell)) return true; } return false; } /// 获取 item 在集合中的偏移位置,不存在时返回 -1。 public static int IndexOf(IEnumerable objects, T item) { if (objects == null) return -1; if (objects is IList list) return list.IndexOf(item); if (item == null) { if (objects is T[] array) { var length = array.Length; for (var i = 0; i < length; i++) { if (array[i] == null) return i; } return -1; } var index = 0; foreach (var obj in objects) { if (obj == null) return index; index++; } return -1; } else { var comparer = EqualityComparer.Default; if (objects is T[] array) { var length = array.Length; for (var i = 0; i < length; i++) { if (comparer.Equals(item, array[i])) return i; } return -1; } var index = 0; foreach (var obj in objects) { if (comparer.Equals(item, obj)) return index; index++; } return -1; } } #endregion #region 类型转换 /// 转换模型类型。 public static TDst[] As(this TSrc[] array) where TDst : class { if (array == null) return null; var count = array.Length; var output = new TDst[count]; for (var i = 0; i < count; i++) { var item = array[i]; if (item == null) continue; output[i] = item as TDst; } return output; } /// 转换模型类型。 public static TDst[] As(this TSrc[] array, Func convert) { if (convert == null) throw new ArgumentNullException(nameof(convert)); if (array == null) return null; var count = array.Length; var output = new TDst[count]; for (var i = 0; i < count; i++) { var item = array[i]; if (item == null) continue; output[i] = convert(item); } return output; } /// 安全转换为 List<> 对象。可指定排除 NULL 值元素。 public static List List(IEnumerable objects, bool excludeNull = false) { if (objects == null) return new List(); var list = new List(); var collection = objects as ICollection; if (collection != null) { list.AddRange(objects); } else { var group = 1024; var added = 0; var capacity = 0; if (objects != null) { foreach (var item in objects) { if (excludeNull && item == null) continue; if (added == capacity) { capacity += group; list.Capacity = capacity; } list.Add(item); added += 1; } } list.Capacity = added; } return list; } /// 安全转换为 <>[] 对象。可指定排除 NULL 值元素。 public static T[] Array(IEnumerable objects, bool excludeNull = false) { if (objects == null) return new T[0]; if (objects is T[]) return (T[])objects; var collection = objects as ICollection; if (collection != null) { var array = new T[collection.Count]; collection.CopyTo(array, 0); return array; } else { var group = 1024; var array = new T[group]; var added = 0; var capacity = 0; foreach (var item in objects) { if (excludeNull && item == null) continue; if (added == capacity) { capacity += group; var temp = new T[capacity]; System.Array.Copy(array, 0, temp, 0, added); array = temp; } array[added] = item; added += 1; } if (added < 1 || added == capacity) return array; var collapsed = new T[added]; System.Array.Copy(array, 0, collapsed, 0, added); return collapsed; } } /// 生成 StringPairs 对象实例为副本。 public static StringPairs StringPairs(NameValueCollection @this) => Apewer.StringPairs.From(@this); /// 转换集合为数组。 /// /// public static Dictionary Dictionary(NameValueCollection collection) { if (collection == null) return null; var count = collection.Count; var dict = new Dictionary(); for (var i = 0; i < count; i++) { var key = collection.GetKey(i); var values = collection.GetValues(i); dict.Add(key, values); } return dict; } /// 转换集合为字典。 /// 字典 Key 的类型。 /// 字典 Value 的类型。 /// 要转换的集合。 /// 根据元素获取 Key 的函数。 /// public static Dictionary Dictionary(IEnumerable items, Func key) { if (items == null) throw new ArgumentNullException(nameof(items)); if (key == null) throw new ArgumentNullException(nameof(key)); var dict = new Dictionary(); foreach (var i in items) { if (i == null) continue; var k = key(i); if (k.IsNull()) continue; if (dict.ContainsKey(k)) continue; dict.Add(k, i); } return dict; } #endregion #region 修改集合 /// 添加多个元素。 public static void Add(List list, params T[] items) { if (list != null && items != null) list.AddRange(items); } /// 添加多个元素。 public static IList Add(IList list, IEnumerable items) { if (list != null && items != null) { foreach (var item in items) list.Add(item); } return list; } /// 添加元素。 public static bool Add(IList> list, TKey key, TValue value) { if (list == null) return false; list.Add(new KeyValuePair(key, value)); return true; } /// 对元素去重,且去除 NULL 值。 public static T[] Distinct(IEnumerable items) { if (items == null) throw new ArgumentNullException(nameof(items)); var count = Count(items); var added = 0; var array = new T[count]; var comparer = EqualityComparer.Default; foreach (var item in items) { if (item == null) continue; var contains = false; foreach (var i in array) { if (comparer.Equals(i, item)) { contains = true; break; } } if (contains) continue; array[added] = item; added++; } if (added < count) { var temp = new T[added]; System.Array.Copy(array, 0, temp, 0, added); array = temp; } return array; } /// 清理集合,去除 NULL 值。 public static T[] Vacuum(this IEnumerable items) => FindAll(items, x => x != null); /// 获取可枚举集合的部分元素。 /// 集合元素的类型。 /// 原集合。 /// 在集合前段要跳过的元素数量。 /// 要获取的元素数量,指定为负数时不限元素数量。 /// 填充器,获取范围超出原集合的部分,使用此方法填充元素;此函数默认返回 的默认值。 /// 数量符合 count 的数组。 public static T[] Slice(IEnumerable objects, int skip = 0, int count = -1, Func stuffer = null) { if (count == 0) return new T[0]; var ab = new ArrayBuilder(); var added = 0; if (skip < 0) { var end = 0 - skip; for (var i = 0; i < end; i++) { ab.Add(stuffer == null ? default : stuffer()); added++; if (count > 0 && added == count) return ab.Export(); } } if (objects != null) { var offset = 0; foreach (var item in objects) { if (offset < skip) { offset++; continue; } ab.Add(item); added++; offset++; if (count > 0 && added == count) return ab.Export(); } } while (added < count) { ab.Add(stuffer == null ? default : stuffer()); added++; } return ab.Export(); } /// 在数组尾部增加元素,生成新数组,不修改原数组。 /// 增加元素后的新数组。 public static T[] Push(this T[] array, T item) { if (array == null) return new T[] { item }; var length = array.Length; var newArray = new T[length + 1]; if (length > 0) System.Array.Copy(array, 0, newArray, 0, length); newArray[length] = item; return newArray; } /// 在数组尾部增加元素,生成新数组,不修改原数组。 /// 增加元素后的新数组。 public static T[] Push(this T[] array, T[] items) { if (array == null) return items ?? new T[0]; if (items == null) { var result = new T[array.Length]; array.CopyTo(result, 0); return result; } else { var length1 = array.Length; var length2 = items.Length; var result = new T[length1 + length2]; if (length1 > 0) System.Array.Copy(array, 0, result, 0, length1); if (length2 > 0) System.Array.Copy(items, 0, result, length1, length2); return result; } } /// 在数组头部增加元素,生成新数组,不修改原数组。 /// 增加元素后的新数组。 public static T[] Unshift(this T[] array, T item) { if (array == null) return new T[] { item }; var length = array.Length; var newArray = new T[length + 1]; newArray[0] = item; if (length > 0) System.Array.Copy(array, 0, newArray, 1, length); return newArray; } /// 在数组头部增加元素,生成新数组,不修改原数组。 /// 增加元素后的新数组。 public static T[] Unshift(this T[] array, T[] items) { if (array == null) return items ?? new T[0]; if (items == null) { var result = new T[array.Length]; array.CopyTo(result, 0); return result; } else { var length1 = array.Length; var length2 = items.Length; var result = new T[length1 + length2]; if (length2 > 0) System.Array.Copy(items, 0, result, 0, length2); if (length1 > 0) System.Array.Copy(array, 0, result, length2, length1); return result; } } #endregion #region 排序 /// 对列表中的元素排序。 public static List Sort(List list, Func comparison) { if (list == null) return null; if (comparison == null) return list; list.Sort(new Comparison(comparison)); return list; } /// 对数组排序。 /// public static T[] Sort(T[] array, Func comparison) { if (array == null) return array; if (comparison == null) return array; System.Array.Sort(array, new Comparison(comparison)); return array; } /// 获取集合中的第一个元素。可指定失败时的默认返回值。 public static T First(IEnumerable collection, T failed = default(T)) { if (collection == null) return failed; var array = collection as T[]; if (array != null) return array.Length > 0 ? array[0] : failed; var list = collection as IList; if (list != null) return list.Count > 0 ? list[0] : failed; foreach (var item in collection) return item; return failed; } /// 获取集合中的最后一个元素。可指定失败时的默认返回值。 public static T Last(IEnumerable collection, T failed = default(T)) { if (collection == null) return failed; var array = collection as T[]; if (array != null) return array.Length > 0 ? array[array.Length - 1] : failed; var list = collection as IList; if (list != null) return list.Count > 0 ? list[list.Count - 1] : failed; var value = failed; foreach (var item in collection) value = item; return value; } /// 对数组升序排序。 /// public static T[] Ascend(T[] array) where T : IComparable { if (array == null) return null; array.Sort((a, b) => a.CompareTo(b)); return array; } /// 对数组升序排序。 /// public static List Ascend(List list) where T : IComparable { if (list == null) return null; list.Sort((a, b) => a.CompareTo(b)); return list; } /// 对数组升序排序。 /// public static void Ascend(T[] array, Func func) where TProp : IComparable { if (array != null && func != null) Sort(array, (a, b) => func(a).CompareTo(func(b))); } /// 对数组降序排序。 /// public static T[] Descend(T[] array) where T : IComparable { if (array == null) return array; Sort(array, (a, b) => 0 - a.CompareTo(b)); return array; } /// 对数组降序排序。 /// public static List Descend(List list) where T : IComparable { if (list == null) return null; list.Sort((a, b) => -a.CompareTo(b)); return list; } /// 对数组降序排序。 /// public static void Descend(T[] array, Func func) where TProp : IComparable { if (array != null && func != null) Sort(array, (a, b) => 0 - func(a).CompareTo(func(b))); } /// 对字典中的键排序。 public static Dictionary SortKey(Dictionary dict, Func comparison) { if (dict == null) return null; if (comparison == null) return null; var list = new List>(dict); list.Sort(new Comparison>((a, b) => comparison(a.Key, b.Key))); dict.Clear(); foreach (var item in list) dict.Add(item.Key, item.Value); return dict; } /// 对字典中的键排序。 public static Dictionary SortKey(Dictionary @this) where TKey : IComparable { return SortKey(@this, (a, b) => a.CompareTo(b)); } /// 对字典中的值排序。 public static Dictionary SortValue(Dictionary dict, Func comparison) { if (dict == null) return null; if (comparison == null) return dict; var list = new List>(dict); list.Sort(new Comparison>((a, b) => comparison(a.Value, b.Value))); dict.Clear(); foreach (var item in list) dict.Add(item.Key, item.Value); return dict; } /// 对字典中的值排序。 public static Dictionary SortValue(Dictionary @this) where TValue : IComparable { return SortValue(@this, (a, b) => a.CompareTo(b)); } #endregion #region params internal static object[] ParseParams(object cells) { var parsed = new ArrayBuilder(); ParseParams(cells, parsed, 1); return parsed; } static void ParseParams(object cells, ArrayBuilder parsed, int depth) { if (cells.IsNull()) return; if (cells is string str) { parsed.Add(cells); return; } if (cells is IList items) { if (depth > 64) { parsed.Add(nameof(IList)); return; } var count = items.Count; for (var i = 0; i < count; i++) { ParseParams(items[i], parsed, depth + 1); } return; } parsed.Add(cells.ToString()); } #endregion #region Find /// 根据条件筛选,将符合条件的元素组成新数组。 public static T[] FindAll(this IEnumerable collection, Predicate match) { if (collection == null) new ArgumentNullException(nameof(collection)); if (match == null) throw new ArgumentNullException(nameof(match)); if (collection is T[] array) { return System.Array.FindAll(array, match); } else if (collection is IList list) { var count = list.Count; var result = new List(count); for (var i = 0; i < count; i++) { var matched = match.Invoke(list[i]); if (matched) result.Add(list[i]); } return result.ToArray(); } else { var result = new List(); foreach (var item in collection) { var matched = match.Invoke(item); if (matched) result.Add(item); } return result.ToArray(); } } /// 根据条件筛选,找到第一个符合条件的元素。 public static T Find(this IEnumerable collection, Predicate match) { if (collection == null) throw new ArgumentNullException(nameof(collection)); if (match == null) throw new ArgumentNullException(nameof(match)); if (collection is T[] array) { return System.Array.Find(array, match); } else if (collection is IList list) { var count = list.Count; for (var i = 0; i < count; i++) { var matched = match.Invoke(list[i]); if (matched) return list[i]; } } else { foreach (var item in collection) { var matched = match.Invoke(item); if (matched) return item; } } return default; } #endregion #region Map /// 遍历集合,转换元素,生成新数组。 /// 输入的元素类型。 /// 输出的元素类型。 /// 要遍历的集合。 /// 转换程序。 /// 新数组的元素类型。 public static TOut[] Map(this IEnumerable collection, Func selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); if (collection == null) return new TOut[0]; return Map(collection, (item, index) => selector.Invoke(item)); } /// 遍历集合,转换元素,生成新数组。 /// 输入的元素类型。 /// 输出的元素类型。 /// 要遍历的集合。 /// 转换程序,提供索引参数(从 0 开始)。 /// 新数组的元素类型。 public static TOut[] Map(this IEnumerable collection, Func selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); if (collection == null) return new TOut[0]; if (collection is TIn[] array) { var count = array.Length; var result = new TOut[count]; for (var i = 0; i < count; i++) { result[i] = selector.Invoke(array[i], i); } return result; } else { var capacity = 0; var count = 0; var list = new List(); foreach (var item in collection) { if (capacity == count) { capacity += 1024; list.Capacity += capacity; } list.Add(selector.Invoke(item, count)); count += 1; } return list.ToArray(); } } #endregion #region ForEach /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 回调。参数为本次遍历的元素。 public static void ForEach(this IEnumerable collection, Action callback) { if (collection == null || callback == null) return; ForEach(collection, (item, index) => { callback.Invoke(item); return JumpStatement.Continue; }); } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。 public static void ForEach(this IEnumerable collection, Action callback) { if (collection == null || callback == null) return; ForEach(collection, (item, index) => { callback.Invoke(item, index); return JumpStatement.Continue; }); } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 回调。参数为本次遍历的元素。 public static void ForEach(this IEnumerable collection, Func callback) { if (collection == null || callback == null) return; ForEach(collection, (item, index) => { var result = callback.Invoke(item); return result; }); } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。返回 true 将继续遍历,返回 false 打断遍历。 public static void ForEach(this IEnumerable collection, Func callback) { if (collection == null || callback == null) return; if (collection is T[] array) { var count = array.Length; for (var i = 0; i < count; i++) { var jump = callback.Invoke(array[i], i); if (jump == JumpStatement.Break) break; } } else { var index = 0; foreach (var item in collection) { var jump = callback.Invoke(item, index); if (jump == JumpStatement.Break) break; index += 1; } } } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 每次遍历的元素数量。 /// 回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。 /// public static void ForEach(this IEnumerable collection, int limit, Action callback) { if (collection == null || callback == null) return; ForEach(collection, limit, (items, index) => { callback.Invoke(items); return JumpStatement.Continue; }); } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 每次遍历的元素数量。 /// 回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。 /// public static void ForEach(this IEnumerable collection, int limit, Action callback) { if (collection == null || callback == null) return; ForEach(collection, limit, (items, index) => { callback.Invoke(items, index); return JumpStatement.Continue; }); } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 每次遍历的元素数量。 /// 回调。参数为本次遍历的元素。 /// public static void ForEach(this IEnumerable collection, int limit, Func callback) { if (collection == null || callback == null) return; ForEach(collection, limit, (items, index) => { var result = callback.Invoke(items); return result; }); } /// 遍历每个元素,执行回调。 /// 元素的类型。 /// 元素的集合。 /// 每次遍历的元素数量。 /// 回调。参数为本次遍历的元素和遍历的索引值,索引值从 0 开始。 /// public static void ForEach(this IEnumerable collection, int limit, Func callback) { if (limit < 1) throw new ArgumentOutOfRangeException(nameof(limit)); if (collection == null) return; if (callback == null) return; if (collection is T[] array) { var total = array.LongLength; var start = 0L; var index = 0; var length = 0L; while (start < total) { length = limit; if (start + length > total) length = total - start; var temp = new T[length]; System.Array.Copy(array, start, temp, 0L, length); var jump = callback.Invoke(temp, index); if (jump == JumpStatement.Break) break; start += length; index += 1; } return; } else { var queue = new Queue(collection); var index = 0; while (queue.Count > 0) { var list = new List(limit); while (list.Count < limit && queue.Count > 0) list.Add(queue.Dequeue()); var temp = list.ToArray(); var jump = callback.Invoke(temp, index); if (jump == JumpStatement.Break) break; index += 1; } } } #endregion #region Join /// 连接多个集合的元素为单个集合。 public static T[] Join(params IEnumerable[] collections) { if (collections == null) return new T[0]; var count = collections.Length; if (count < 1) return new T[0]; var result = new List(); foreach (var collection in collections) { if (collection == null) continue; foreach (var item in collection) { result.Add(item); } } return result.ToArray(); } #endregion } }