using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; namespace Masuit.Tools; /// /// /// public static class IEnumerableExtensions { #if NETFRAMEWORK public static IEnumerable Append(this IEnumerable source, T item) { return source.Concat([item]); } #endif /// /// 按字段属性判等取交集 /// /// /// /// /// /// /// public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func condition) { return first.Where(f => second.Any(s => condition(f, s))); } /// /// 按字段属性判等取交集 /// /// /// /// /// /// /// public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector) { return first.IntersectBy(second, keySelector, null); } /// /// 按字段属性判等取交集 /// /// /// /// /// /// /// /// public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); return IntersectByIterator(first, second, keySelector, comparer); } private static IEnumerable IntersectByIterator(IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer) { var set = new HashSet(second.Select(keySelector), comparer); foreach (var item in first.Where(source => set.Remove(keySelector(source)))) { yield return item; } } /// /// 多个集合取交集元素 /// /// /// /// public static IEnumerable IntersectAll(this IEnumerable> source) { return source.Aggregate((current, item) => current.Intersect(item)); } /// /// 多个集合取交集元素 /// /// /// /// /// /// public static IEnumerable IntersectAll(this IEnumerable> source, Func keySelector) { return source.Aggregate((current, item) => current.IntersectBy(item, keySelector)); } /// /// 多个集合取交集元素 /// /// /// /// /// /// /// public static IEnumerable IntersectAll(this IEnumerable> source, Func keySelector, IEqualityComparer comparer) { return source.Aggregate((current, item) => current.IntersectBy(item, keySelector, comparer)); } /// /// 多个集合取交集元素 /// /// /// /// /// public static IEnumerable IntersectAll(this IEnumerable> source, IEqualityComparer comparer) { return source.Aggregate((current, item) => current.Intersect(item, comparer)); } /// /// 按字段属性判等取差集 /// /// /// /// /// /// /// public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func condition) { return first.Where(f => !second.Any(s => condition(f, s))); } /// /// 按字段属性判等取差集 /// /// /// /// /// public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector) { // 将 second 集合转换为 HashSet 以提高查找效率 var keys = new HashSet(second.Select(keySelector)); // 使用 Lookup 来分组 first 集合,并过滤掉 second 集合中存在的元素 var firstLookup = first.ToLookup(keySelector); return firstLookup.Where(g => !keys.Contains(g.Key)).SelectMany(grouping => grouping); } #if NET6_0_OR_GREATER #else /// /// 按字段去重 /// /// /// /// /// /// public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); var set = new HashSet(); return source.Where(item => set.Add(keySelector(item))); } /// /// 按字段属性判等取交集 /// /// /// /// /// /// /// public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector) { return first.IntersectBy(second, keySelector, null); } /// /// 按字段属性判等取交集 /// /// /// /// /// /// /// /// public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); return IntersectByIterator(first, second, keySelector, comparer); } private static IEnumerable IntersectByIterator(IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer) { var set = new HashSet(second, comparer); return first.Where(source => set.Remove(keySelector(source))); } /// /// 按字段属性判等取差集 /// /// /// /// /// /// /// public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector) { return first.ExceptBy(second, keySelector, null); } /// /// 按字段属性判等取差集 /// /// /// /// /// /// /// /// /// public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); return ExceptByIterator(first, second, keySelector, comparer); } private static IEnumerable ExceptByIterator(IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer) { var set = new HashSet(second, comparer); return first.Where(source => set.Add(keySelector(source))); } #endif /// /// 添加多个元素 /// /// /// /// public static void AddRange(this ICollection @this, params T[] values) { foreach (var obj in values) { @this.Add(obj); } } /// /// 添加多个元素 /// /// /// /// public static void AddRange(this ICollection @this, IEnumerable values) { foreach (var obj in values) { @this.Add(obj); } } /// /// 添加多个元素 /// /// /// /// public static void AddRange(this ConcurrentBag @this, params T[] values) { foreach (var obj in values) { @this.Add(obj); } } /// /// 添加多个元素 /// /// /// /// public static void AddRange(this ConcurrentQueue @this, params T[] values) { foreach (var obj in values) { @this.Enqueue(obj); } } /// /// 添加符合条件的多个元素 /// /// /// /// /// public static void AddRangeIf(this ICollection @this, Func predicate, params T[] values) { foreach (var obj in values.Where(predicate)) { @this.Add(obj); } } /// /// 添加符合条件的多个元素 /// /// /// /// /// public static void AddRangeIf(this ConcurrentBag @this, Func predicate, params T[] values) { foreach (var obj in values.Where(predicate)) { @this.Add(obj); } } /// /// 添加符合条件的多个元素 /// /// /// /// /// public static void AddRangeIf(this ConcurrentQueue @this, Func predicate, params T[] values) { foreach (var obj in values.Where(predicate)) { @this.Enqueue(obj); } } /// /// 符合条件则添加元素 /// /// /// /// /// public static ICollection AddRangeIf(this ICollection @this, Func predicate, IEnumerable values) { if (predicate()) { foreach (var value in values) { @this.Add(value); } } return @this; } /// /// 符合条件则添加元素 /// /// /// /// /// public static ICollection AddRangeIf(this ICollection @this, bool predicate, IEnumerable values) { if (predicate) { foreach (var value in values) { @this.Add(value); } } return @this; } /// /// 符合条件则添加元素 /// /// /// /// /// public static ConcurrentBag AddRangeIf(this ConcurrentBag @this, Func predicate, IEnumerable values) { if (predicate()) { foreach (var value in values) { @this.Add(value); } } return @this; } /// /// 符合条件则添加元素 /// /// /// /// /// public static ConcurrentBag AddRangeIf(this ConcurrentBag @this, bool predicate, IEnumerable values) { if (predicate) { foreach (var value in values) { @this.Add(value); } } return @this; } /// /// 符合条件则添加元素 /// /// /// /// /// public static ConcurrentQueue AddRangeIf(this ConcurrentQueue @this, Func predicate, IEnumerable values) { if (predicate()) { foreach (var value in values) { @this.Enqueue(value); } } return @this; } /// /// 符合条件则添加元素 /// /// /// /// /// public static ConcurrentQueue AddRangeIf(this ConcurrentQueue @this, bool predicate, IEnumerable values) { if (predicate) { foreach (var value in values) { @this.Enqueue(value); } } return @this; } /// /// 添加不重复的元素 /// /// /// /// public static void AddRangeIfNotContains(this ICollection @this, params T[] values) { foreach (var obj in values.Where(obj => !@this.Contains(obj))) { @this.Add(obj); } } /// /// 符合条件则添加一个元素 /// /// /// /// /// public static ICollection AppendIf(this ICollection @this, Func predicate, T value) { if (predicate()) { @this.Add(value); } return @this; } /// /// 符合条件则添加一个元素 /// /// /// /// /// public static ICollection AppendIf(this ICollection @this, bool predicate, T value) { if (predicate) { @this.Add(value); } return @this; } /// /// 符合条件则添加一个元素 /// /// /// /// /// public static IEnumerable AppendIf(this IEnumerable @this, Func predicate, T value) { return predicate() ? @this.Append(value) : @this; } /// /// 符合条件则添加一个元素 /// /// /// /// /// public static IEnumerable AppendIf(this IEnumerable @this, bool predicate, T value) { return predicate ? @this.Append(value) : @this; } /// /// 移除符合条件的元素 /// /// /// /// public static void RemoveWhere(this ICollection @this, Func @where) { var list = @this.Where(where).ToList(); foreach (var obj in list) { @this.Remove(obj); } } /// /// 在元素之后添加元素 /// /// /// /// 条件 /// 值 public static void InsertAfter(this IList list, Func condition, T value) { foreach (var index in list.Select((item, index) => new { item, index }).Where(p => condition(p.item)).OrderByDescending(p => p.index).Select(t => t.index)) { if (index + 1 == list.Count) { list.Add(value); } else { list.Insert(index + 1, value); } } } /// /// 在元素之后添加元素 /// /// /// /// 索引位置 /// 值 public static void InsertAfter(this IList list, int index, T value) { foreach (var i in list.Select((v, i) => new { Value = v, Index = i }).Where(p => p.Index == index).OrderByDescending(p => p.Index).Select(t => t.Index)) { if (i + 1 == list.Count) { list.Add(value); } else { list.Insert(i + 1, value); } } } /// /// 转HashSet /// /// /// /// /// /// public static HashSet ToHashSet(this IEnumerable source, Func selector) { return new HashSet(source.Select(selector)); } /// /// 转SortedSet /// /// /// /// /// public static SortedSet ToSortedSet(this IEnumerable source, IComparer comparer = null) { return comparer == null ? [.. source] : new SortedSet(source, comparer); } /// /// 转SortedSet /// /// /// /// /// /// /// public static SortedSet ToSortedSet(this IEnumerable source, Func selector, IComparer comparer = null) { return comparer == null ? [.. source.Select(selector)] : new SortedSet(source.Select(selector), comparer); } /// /// 转Queue /// /// /// /// public static Queue ToQueue(this IEnumerable source) { return new Queue(source); } /// /// 转Queue /// /// /// /// /// /// public static Queue ToQueue(this IEnumerable source, Func selector) { return new Queue(source.Select(selector)); } /// /// 遍历IEnumerable /// /// /// 回调方法 /// public static void ForEach(this IEnumerable objs, Action action) { foreach (var o in objs) { action(o); } } /// /// 异步foreach /// /// /// /// 最大并行数 /// /// /// public static async Task ForeachAsync(this IEnumerable source, Func action, int maxParallelCount, CancellationToken cancellationToken = default) { if (Debugger.IsAttached) { foreach (var item in source) { await action(item); } return; } var list = new List(); foreach (var item in source) { if (cancellationToken.IsCancellationRequested) { return; } list.Add(action(item)); if (list.Count(t => !t.IsCompleted) >= maxParallelCount) { await Task.WhenAny(list); list.RemoveAll(t => t.IsCompleted); } } await Task.WhenAll(list); } /// /// 异步foreach /// /// /// /// /// /// public static Task ForeachAsync(this IEnumerable source, Func action, CancellationToken cancellationToken = default) { if (source is ICollection collection) { return ForeachAsync(collection, action, collection.Count, cancellationToken); } var list = source.ToList(); return ForeachAsync(list, action, list.Count, cancellationToken); } /// /// 异步Select /// /// /// /// /// /// public static Task SelectAsync(this IEnumerable source, Func> selector) { return Task.WhenAll(source.Select(selector)); } /// /// 异步Select /// /// /// /// /// /// public static Task SelectAsync(this IEnumerable source, Func> selector) { return Task.WhenAll(source.Select(selector)); } /// /// 异步Select /// /// /// /// /// /// 最大并行数 /// /// public static async Task> SelectAsync(this IEnumerable source, Func> selector, int maxParallelCount, CancellationToken cancellationToken = default) { var results = new List(); var tasks = new List>(); foreach (var item in source) { if (cancellationToken.IsCancellationRequested) { break; } var task = selector(item); tasks.Add(task); if (tasks.Count >= maxParallelCount) { await Task.WhenAny(tasks); var completedTasks = tasks.Where(t => t.IsCompleted).ToArray(); results.AddRange(completedTasks.Select(t => t.Result)); tasks.RemoveWhere(t => completedTasks.Contains(t)); } } results.AddRange(await Task.WhenAll(tasks)); return results; } /// /// 异步Select /// /// /// /// /// /// 最大并行数 /// /// public static async Task> SelectAsync(this IEnumerable source, Func> selector, int maxParallelCount, CancellationToken cancellationToken = default) { var results = new List(); var tasks = new List>(); int index = 0; foreach (var item in source) { if (cancellationToken.IsCancellationRequested) { break; } var task = selector(item, index); tasks.Add(task); Interlocked.Add(ref index, 1); if (tasks.Count >= maxParallelCount) { await Task.WhenAny(tasks); var completedTasks = tasks.Where(t => t.IsCompleted).ToArray(); results.AddRange(completedTasks.Select(t => t.Result)); tasks.RemoveWhere(t => completedTasks.Contains(t)); } } results.AddRange(await Task.WhenAll(tasks)); return results; } /// /// 异步SelectMany /// /// /// /// /// /// public static Task> SelectManyAsync(this IEnumerable source, Func>> selector) { return Task.WhenAll(source.Select(selector)).ContinueWith(t => t.Result.SelectMany(_ => _)); } /// /// 异步SelectMany /// /// /// /// /// /// public static Task> SelectManyAsync(this IEnumerable source, Func>> selector) { return Task.WhenAll(source.Select(selector)).ContinueWith(t => t.Result.SelectMany(_ => _)); } /// /// 异步SelectMany /// /// /// /// /// /// 最大并行数 /// /// public static async Task> SelectManyAsync(this IEnumerable source, Func>> selector, int maxParallelCount, CancellationToken cancellationToken = default) { var results = new List(); var tasks = new List>>(); foreach (var item in source) { if (cancellationToken.IsCancellationRequested) { break; } var task = selector(item); tasks.Add(task); if (tasks.Count >= maxParallelCount) { await Task.WhenAny(tasks); var completedTasks = tasks.Where(t => t.IsCompleted).ToArray(); results.AddRange(completedTasks.SelectMany(t => t.Result)); tasks.RemoveWhere(t => completedTasks.Contains(t)); } } results.AddRange(await Task.WhenAll(tasks).ContinueWith(t => t.Result.SelectMany(_ => _), cancellationToken)); return results; } /// /// 异步SelectMany /// /// /// /// /// /// 最大并行数 /// /// public static async Task> SelectManyAsync(this IEnumerable source, Func>> selector, int maxParallelCount, CancellationToken cancellationToken = default) { var results = new List(); var tasks = new List>>(); int index = 0; foreach (var item in source) { if (cancellationToken.IsCancellationRequested) { break; } var task = selector(item, index); tasks.Add(task); Interlocked.Add(ref index, 1); if (tasks.Count >= maxParallelCount) { await Task.WhenAny(tasks); var completedTasks = tasks.Where(t => t.IsCompleted).ToArray(); results.AddRange(completedTasks.SelectMany(t => t.Result)); tasks.RemoveWhere(t => completedTasks.Contains(t)); } } results.AddRange(await Task.WhenAll(tasks).ContinueWith(t => t.Result.SelectMany(_ => _), cancellationToken)); return results; } /// /// 异步For /// /// /// /// /// 最大并行数 /// 取消口令 /// public static async Task ForAsync(this IEnumerable source, Func selector, int maxParallelCount, CancellationToken cancellationToken = default) { int index = 0; if (Debugger.IsAttached) { foreach (var item in source) { await selector(item, index); index++; } return; } var list = new List(); foreach (var item in source) { if (cancellationToken.IsCancellationRequested) { return; } list.Add(selector(item, index)); Interlocked.Add(ref index, 1); if (list.Count >= maxParallelCount) { await Task.WhenAny(list); list.RemoveAll(t => t.IsCompleted); } } await Task.WhenAll(list); } /// /// 异步For /// /// /// /// /// 取消口令 /// public static Task ForAsync(this IEnumerable source, Func selector, CancellationToken cancellationToken = default) { if (source is ICollection collection) { return ForAsync(collection, selector, collection.Count, cancellationToken); } var list = source.ToList(); return ForAsync(list, selector, list.Count, cancellationToken); } /// /// 取最大值 /// /// /// /// /// /// public static TResult MaxOrDefault(this IQueryable source, Expression> selector) => source.Select(selector).DefaultIfEmpty().Max(); /// /// 取最大值 /// /// /// /// /// /// /// public static TResult MaxOrDefault(this IQueryable source, Expression> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max(); /// /// 取最大值 /// /// /// /// public static TSource MaxOrDefault(this IQueryable source) => source.DefaultIfEmpty().Max(); /// /// 取最大值 /// /// /// /// /// public static TSource MaxOrDefault(this IQueryable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max(); /// /// 取最大值 /// /// /// /// /// /// /// public static TResult MaxOrDefault(this IEnumerable source, Func selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max(); /// /// 取最大值 /// /// /// /// /// /// public static TResult MaxOrDefault(this IEnumerable source, Func selector) => source.Select(selector).DefaultIfEmpty().Max(); /// /// 取最大值 /// /// /// /// public static TSource MaxOrDefault(this IEnumerable source) => source.DefaultIfEmpty().Max(); /// /// 取最大值 /// /// /// /// /// public static TSource MaxOrDefault(this IEnumerable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max(); /// /// 取最小值 /// /// /// /// /// /// public static TResult MinOrDefault(this IQueryable source, Expression> selector) => source.Select(selector).DefaultIfEmpty().Min(); /// /// 取最小值 /// /// /// /// /// /// /// public static TResult MinOrDefault(this IQueryable source, Expression> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min(); /// /// 取最小值 /// /// /// /// public static TSource MinOrDefault(this IQueryable source) => source.DefaultIfEmpty().Min(); /// /// 取最小值 /// /// /// /// /// public static TSource MinOrDefault(this IQueryable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min(); /// /// 取最小值 /// /// /// /// /// /// public static TResult MinOrDefault(this IEnumerable source, Func selector) => source.Select(selector).DefaultIfEmpty().Min(); /// /// 取最小值 /// /// /// /// /// /// /// public static TResult MinOrDefault(this IEnumerable source, Func selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min(); /// /// 取最小值 /// /// /// /// public static TSource MinOrDefault(this IEnumerable source) => source.DefaultIfEmpty().Min(); /// /// 取最小值 /// /// /// /// /// public static TSource MinOrDefault(this IEnumerable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min(); /// /// 标准差 /// /// /// /// /// /// public static TResult StandardDeviation(this IEnumerable source, Func selector) where TResult : IConvertible { return StandardDeviation(source.Select(t => selector(t).ConvertTo())).ConvertTo(); } /// /// 标准差 /// /// /// /// public static T StandardDeviation(this IEnumerable source) where T : IConvertible { return StandardDeviation(source.Select(t => t.ConvertTo())).ConvertTo(); } /// /// 标准差 /// /// /// public static double StandardDeviation(this IEnumerable source) { double result = 0; var list = source as ICollection ?? source.ToList(); int count = list.Count; if (count > 1) { var avg = list.Average(); var sum = list.Sum(d => (d - avg) * (d - avg)); result = Math.Sqrt(sum / count); } return result; } /// /// 随机排序 /// /// /// /// public static IOrderedEnumerable OrderByRandom(this IEnumerable source) { return source.OrderBy(_ => Guid.NewGuid()); } /// /// 序列相等 /// /// /// /// /// /// public static bool SequenceEqual(this IEnumerable first, IEnumerable second, Func condition) { if (first is ICollection source1 && second is ICollection source2) { if (source1.Count != source2.Count) { return false; } if (source1 is IList list1 && source2 is IList list2) { int count = source1.Count; for (int index = 0; index < count; ++index) { if (!condition(list1[index], list2[index])) { return false; } } return true; } } using IEnumerator enumerator1 = first.GetEnumerator(); using IEnumerator enumerator2 = second.GetEnumerator(); while (enumerator1.MoveNext()) { if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current)) { return false; } } return !enumerator2.MoveNext(); } /// /// 序列相等 /// /// /// /// /// /// /// public static bool SequenceEqual(this IEnumerable first, IEnumerable second, Func condition) { if (first is ICollection source1 && second is ICollection source2) { if (source1.Count != source2.Count) { return false; } if (source1 is IList list1 && source2 is IList list2) { int count = source1.Count; for (int index = 0; index < count; ++index) { if (!condition(list1[index], list2[index])) { return false; } } return true; } } using IEnumerator enumerator1 = first.GetEnumerator(); using IEnumerator enumerator2 = second.GetEnumerator(); while (enumerator1.MoveNext()) { if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current)) { return false; } } return !enumerator2.MoveNext(); } /// /// 对比两个集合哪些是新增的、删除的、修改的 /// /// 新集合 /// 旧集合 /// public static (List adds, List remove, List updates) CompareChanges(this IEnumerable first, IEnumerable second) { first ??= new List(); second ??= new List(); var firstSource = first as ICollection ?? first.ToList(); var secondSource = second as ICollection ?? second.ToList(); var add = firstSource.Except(secondSource).ToList(); var remove = secondSource.Except(firstSource).ToList(); var update = firstSource.Intersect(secondSource).ToList(); return (add, remove, update); } /// /// 对比两个集合哪些是新增的、删除的、修改的 /// /// 对比因素 /// /// 新集合 /// 旧集合 /// 对比因素(可唯一确定元素的字段) /// public static (List adds, List remove, List updates) CompareChanges(this IEnumerable first, IEnumerable second, Func keySelector) { return CompareChanges(first, second, keySelector, keySelector); } /// /// 对比两个集合哪些是新增的、删除的、修改的(大数据集时性能不佳,请考虑使用其他重载) /// /// /// /// 新集合 /// 旧集合 /// 对比因素条件 /// [Obsolete("大数据集时性能不佳,请考虑使用其他重载")] public static (List adds, List remove, List updates) CompareChanges(this IEnumerable first, IEnumerable second, Func condition) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (condition == null) throw new ArgumentNullException(nameof(condition)); var adds = new List(); var removes = new List(); var updates = new List(); var secondSet = new HashSet(second); foreach (var item in first) { var match = secondSet.FirstOrDefault(s => condition(item, s)); if (match != null) { updates.Add(item); secondSet.Remove(match); } else { adds.Add(item); } } removes.AddRange(secondSet); return (adds, removes, updates); } /// /// 对比两个集合哪些是新增的、删除的、修改的 /// /// 集合1 /// 集合2 /// 对比因素 /// 新集合 /// 旧集合 /// 集合1的对比因素(可唯一确定元素的字段) /// 集合2的对比因素(可唯一确定元素的字段) /// public static (List adds, List remove, List updates) CompareChanges(this IEnumerable first, IEnumerable second, Func firstKeySelector, Func secondKeySelector) { first ??= new List(); second ??= new List(); var firstLookup = first.ToLookup(firstKeySelector); var secondLookup = second.ToLookup(secondKeySelector); var adds = new List(); var removes = new List(); var updates = new List(); foreach (var kvp in firstLookup) { if (secondLookup.Contains(kvp.Key)) { updates.AddRange(kvp); } else { adds.AddRange(kvp); } } foreach (var kvp in secondLookup.Where(kvp => !firstLookup.Contains(kvp.Key))) { removes.AddRange(kvp); } return (adds, removes, updates); } /// /// 对比两个集合哪些是新增的、删除的、修改的 /// /// 新集合 /// 旧集合 /// public static (List adds, List remove, List<(T first, T second)> updates) CompareChangesPlus(this IEnumerable first, IEnumerable second) { first ??= new List(); second ??= new List(); var firstSource = first as ICollection ?? first.ToList(); var secondSource = second as ICollection ?? second.ToList(); var add = firstSource.Except(secondSource).ToList(); var remove = secondSource.Except(firstSource).ToList(); var updates = firstSource.Intersect(secondSource).Select(t1 => (t1, secondSource.FirstOrDefault(t2 => t1.Equals(t2)))).ToList(); return (add, remove, updates); } /// /// 对比两个集合哪些是新增的、删除的、修改的 /// /// 新集合 /// 旧集合 /// 对比因素 /// public static (List adds, List remove, List<(T first, T second)> updates) CompareChangesPlus(this IEnumerable first, IEnumerable second, Func keySelector) { return CompareChangesPlus(first, second, keySelector, keySelector); } /// /// 对比两个集合哪些是新增的、删除的、修改的(大数据集时性能不佳,请考虑使用其他重载) /// /// /// /// 新集合 /// 旧集合 /// 对比因素条件 /// [Obsolete("大数据集时性能不佳,请考虑使用其他重载")] public static (List adds, List remove, List<(T1 first, T2 second)> updates) CompareChangesPlus( this IEnumerable first, IEnumerable second, Func condition) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (condition == null) throw new ArgumentNullException(nameof(condition)); var adds = new List(); var removes = new List(); var updates = new List<(T1 first, T2 second)>(); var secondSet = new HashSet(second); foreach (var item in first) { var match = secondSet.FirstOrDefault(s => condition(item, s)); if (match != null) { updates.Add((item, match)); secondSet.Remove(match); } else { adds.Add(item); } } removes.AddRange(secondSet); return (adds, removes, updates); } /// /// 对比两个集合哪些是新增的、删除的、修改的 /// /// /// /// /// 新集合 /// 旧集合 /// 集合1的对比因素(可唯一确定元素的字段) /// 集合2的对比因素(可唯一确定元素的字段) /// public static (List adds, List remove, List<(T1 first, T2 second)> updates) CompareChangesPlus(this IEnumerable first, IEnumerable second, Func firstKeySelector, Func secondKeySelector) { first ??= new List(); second ??= new List(); var lookup1 = first.ToLookup(firstKeySelector); var lookup2 = second.ToLookup(secondKeySelector); var add = new List(); var remove = new List(); var updates = new List<(T1 first, T2 second)>(); foreach (var x in lookup1) { if (lookup2.Contains(x.Key)) { updates.Add((x.First(), lookup2[x.Key].First())); } else { add.AddRange(x); } } foreach (var x in lookup2.Where(x => !lookup1.Contains(x.Key))) { remove.AddRange(x); } return (add, remove, updates); } /// /// 将集合声明为非null集合 /// /// /// /// public static List AsNotNull(this List list) { return list ?? new List(); } /// /// 将集合声明为非null集合 /// /// /// /// public static IEnumerable AsNotNull(this IEnumerable list) { return list ?? new List(); } /// /// 满足条件时执行筛选条件 /// /// /// /// /// /// public static IEnumerable WhereIf(this IEnumerable source, bool condition, Func where) { return condition ? source.Where(where) : source; } /// /// 满足条件时执行筛选条件 /// /// /// /// /// /// public static IEnumerable WhereIf(this IEnumerable source, Func condition, Func where) { return condition() ? source.Where(where) : source; } /// /// 满足条件时执行筛选条件 /// /// /// /// /// /// public static IQueryable WhereIf(this IQueryable source, bool condition, Expression> where) { return condition ? source.Where(where) : source; } /// /// 满足条件时执行筛选条件 /// /// /// /// /// /// public static IQueryable WhereIf(this IQueryable source, Func condition, Expression> where) { return condition() ? source.Where(where) : source; } /// /// 改变元素的索引位置 /// /// /// 集合 /// 元素 /// 索引值 /// public static IList ChangeIndex(this IList list, T item, int index) { if (item is null) { throw new ArgumentNullException(nameof(item)); } ChangeIndexInternal(list, item, index); return list; } /// /// 改变元素的索引位置 /// /// /// 集合 /// 元素定位条件 /// 索引值 public static IList ChangeIndex(this IList list, Func condition, int index) { var item = list.FirstOrDefault(condition); if (item != null) { ChangeIndexInternal(list, item, index); } return list; } private static void ChangeIndexInternal(IList list, T item, int index) { index = Math.Max(0, index); index = Math.Min(list.Count - 1, index); list.Remove(item); list.Insert(index, item); } }