using System;
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
{
///
/// 按字段属性判等取交集
///
///
///
///
///
///
///
public static IEnumerable IntersectBy(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 condition)
{
return first.Where(f => !second.Any(s => condition(f, s)));
}
#if NET6_0_OR_GREATER
#else
///
/// 按字段去重
///
///
///
///
///
///
public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector)
{
var hash = new HashSet();
return source.Where(p => hash.Add(keySelector(p)));
}
///
/// 按字段属性判等取交集
///
///
///
///
///
///
///
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);
foreach (var source in first)
{
if (set.Remove(keySelector(source)))
yield return 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);
foreach (var source in first)
{
if (set.Add(keySelector(source)))
yield return 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)
{
if (predicate(obj))
{
@this.Add(obj);
}
}
}
///
/// 添加符合条件的多个元素
///
///
///
///
///
public static void AddRangeIf(this ConcurrentBag @this, Func predicate, params T[] values)
{
foreach (var obj in values)
{
if (predicate(obj))
{
@this.Add(obj);
}
}
}
///
/// 添加符合条件的多个元素
///
///
///
///
///
public static void AddRangeIf(this ConcurrentQueue @this, Func predicate, params T[] values)
{
foreach (var obj in values)
{
if (predicate(obj))
{
@this.Enqueue(obj);
}
}
}
///
/// 添加不重复的元素
///
///
///
///
public static void AddRangeIfNotContains(this ICollection @this, params T[] values)
{
foreach (T obj in values)
{
if (!@this.Contains(obj))
{
@this.Add(obj);
}
}
}
///
/// 移除符合条件的元素
///
///
///
///
public static void RemoveWhere(this ICollection @this, Func @where)
{
foreach (var obj in @this.Where(where).ToList())
{
@this.Remove(obj);
}
}
///
/// 在元素之后添加元素
///
///
///
/// 条件
/// 值
public static void InsertAfter(this IList list, Func condition, T value)
{
foreach (var item in list.Select((item, index) => new
{
item,
index
}).Where(p => condition(p.item)).OrderByDescending(p => p.index))
{
if (item.index + 1 == list.Count)
{
list.Add(value);
}
else
{
list.Insert(item.index + 1, value);
}
}
}
///
/// 在元素之后添加元素
///
///
///
/// 索引位置
/// 值
public static void InsertAfter(this IList list, int index, T value)
{
foreach (var item in list.Select((v, i) => new
{
Value = v,
Index = i
}).Where(p => p.Index == index).OrderByDescending(p => p.Index))
{
if (item.Index + 1 == list.Count)
{
list.Add(value);
}
else
{
list.Insert(item.Index + 1, value);
}
}
}
///
/// 转HashSet
///
///
///
///
///
///
public static HashSet ToHashSet(this IEnumerable source, Func selector)
{
var set = new HashSet();
set.UnionWith(source.Select(selector));
return set;
}
///
/// 遍历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 >= maxParallelCount)
{
await Task.WhenAll(list);
list.Clear();
}
}
await Task.WhenAll(list);
}
///
/// 异步foreach
///
///
///
///
///
public static Task ForeachAsync(this IEnumerable source, Func action, CancellationToken cancellationToken = default)
{
return ForeachAsync(source, action, source.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)
{
var results = new List();
var tasks = new List>();
foreach (var item in source)
{
var task = selector(item);
tasks.Add(task);
if (tasks.Count >= maxParallelCount)
{
results.AddRange(await Task.WhenAll(tasks));
tasks.Clear();
}
}
results.AddRange(await Task.WhenAll(tasks));
return results;
}
///
/// 异步Select
///
///
///
///
///
/// 最大并行数
///
public static async Task> SelectAsync(this IEnumerable source, Func> selector, int maxParallelCount)
{
var results = new List();
var tasks = new List>();
int index = 0;
foreach (var item in source)
{
var task = selector(item, index++);
tasks.Add(task);
if (tasks.Count >= maxParallelCount)
{
results.AddRange(await Task.WhenAll(tasks));
tasks.Clear();
}
}
results.AddRange(await Task.WhenAll(tasks));
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.WhenAll(list);
list.Clear();
}
}
await Task.WhenAll(list);
}
///
/// 异步For
///
///
///
///
/// 取消口令
///
public static Task ForAsync(this IEnumerable source, Func selector, CancellationToken cancellationToken = default)
{
return ForAsync(source, selector, source.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;
int count = source.Count();
if (count > 1)
{
double avg = source.Average();
double sum = source.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, Func condition)
{
var add = first.ExceptBy(second, condition).ToList();
var remove = second.ExceptBy(first, (s, f) => condition(f, s)).ToList();
var update = first.IntersectBy(second, condition).ToList();
return (add, remove, update);
}
///
/// 对比两个集合哪些是新增的、删除的、修改的
///
///
///
///
///
/// 对比因素条件
///
public static (List adds, List remove, List<(T1 first, T2 second)> updates) CompareChangesPlus(this IEnumerable first, IEnumerable second, Func condition)
{
var add = first.ExceptBy(second, condition).ToList();
var remove = second.ExceptBy(first, (s, f) => condition(f, s)).ToList();
var updates = first.IntersectBy(second, condition).Select(t1 => (t1, second.FirstOrDefault(t2 => condition(t1, t2)))).ToList();
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);
}
}
}