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