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