using NCC.Dependency;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace NCC.Common.Extension
{
///
/// Enumerable集合扩展方法
///
[SuppressSniffer]
public static class EnumerableExtensions
{
/// 断言集合中的元素符合指定表达式,否则抛出异常
/// 集合项类型
/// 源集合
/// 元素判断表达式
/// 异常选择器
/// 筛选过的集合
public static IEnumerable Assert(this IEnumerable source,
Func predicate,
Func errorSelector = null)
{
foreach (T item in source)
{
bool success = predicate(item);
if (!success)
{
throw errorSelector?.Invoke(item) ?? new InvalidOperationException("Sequence contains an invalid item.");
}
yield return item;
}
}
///
/// 确定第一个序列的末尾是否等价于第二个序列。
///
///
/// 第一个序列
/// 第二个序列
///
public static bool EndsWith(this IEnumerable first, IEnumerable second)
{
return EndsWith(first, second, null);
}
///
/// 确定第一个序列的末尾是否等价于第二个序列
///
///
/// 第一个序列
/// 第二个序列
/// 元素比较方式
///
public static bool EndsWith(this IEnumerable first, IEnumerable second, IEqualityComparer comparer)
{
if (first == null) throw new ArgumentNullException(nameof(first));
if (second == null) throw new ArgumentNullException(nameof(second));
comparer = comparer ?? EqualityComparer.Default;
int? secondCount = second.TryGetCollectionCount();
if (secondCount != null)
{
int? firstCount = first.TryGetCollectionCount();
if (firstCount != null && secondCount > firstCount)
{
return false;
}
return Impl(second, secondCount.Value);
}
List secondList;
return Impl(secondList = second.ToList(), secondList.Count);
bool Impl(IEnumerable snd, int count)
{
using (var firstIter = first.Reverse().Take(count).Reverse().GetEnumerator())
{
return snd.All(item => firstIter.MoveNext() && comparer.Equals(firstIter.Current, item));
}
}
}
///
/// 打乱一个集合的项顺序,将一个集合洗牌
///
public static IEnumerable Shuffle(this IEnumerable source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return source.OrderBy(m => Guid.NewGuid());
}
///
/// 将集合展开并分别转换成字符串,再以指定的分隔符衔接,拼成一个字符串返回。默认分隔符为逗号
///
/// 要处理的集合
/// 分隔符,默认为逗号
/// 拼接后的字符串
public static string ExpandAndToString(this IEnumerable collection, string separator = ",")
{
return collection.ExpandAndToString(item => item?.ToString() ?? string.Empty, separator);
}
///
/// 循环集合的每一项,调用委托生成字符串,返回合并后的字符串。默认分隔符为逗号
///
/// 待处理的集合
/// 单个集合项的转换委托
/// 分隔符,默认为逗号
/// 泛型类型
///
public static string ExpandAndToString(this IEnumerable collection, Func itemFormatFunc, string separator = ",")
{
collection = collection as IList ?? collection.ToList();
if (!collection.Any())
{
return string.Empty;
}
StringBuilder sb = new StringBuilder();
int i = 0;
int count = collection.Count();
foreach (T item in collection)
{
if (i == count - 1)
{
sb.Append(itemFormatFunc(item));
}
else
{
sb.Append(itemFormatFunc(item) + separator);
}
i++;
}
return sb.ToString();
}
///
/// 集合是否为空
///
/// 要处理的集合
/// 动态类型
/// 为空返回True,不为空返回False
public static bool IsEmpty(this IEnumerable collection)
{
collection = collection as IList ?? collection.ToList();
return !collection.Any();
}
///
/// 根据第三方条件是否为真来决定是否执行指定条件的查询
///
/// 要查询的源
/// 查询条件
/// 第三方条件
/// 动态类型
/// 查询的结果
public static IEnumerable WhereIf(this IEnumerable source, Func predicate, bool condition)
{
source = source as IList ?? source.ToList();
return condition ? source.Where(predicate) : source;
}
///
/// 将字符串集合按指定前缀排序
///
public static IEnumerable OrderByPrefixes(this IEnumerable source, Func keySelector, params string[] prefixes)
{
List all = source.OrderBy(keySelector).ToList();
List result = new List();
foreach (string prefix in prefixes)
{
List tmpList = all.Where(m => keySelector(m).StartsWith(prefix)).OrderBy(keySelector).ToList();
all = all.Except(tmpList).ToList();
result.AddRange(tmpList);
}
result.AddRange(all);
return result;
}
///
/// 根据指定条件返回集合中不重复的元素
///
/// 动态类型
/// 动态筛选条件类型
/// 要操作的源
/// 重复数据筛选条件
/// 不重复元素的集合
public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector)
{
source = source as IList ?? source.ToList();
return source.GroupBy(keySelector).Select(group => group.First());
}
#region Internal
internal static int? TryGetCollectionCount(this IEnumerable source)
{
switch (source)
{
case null:
throw new ArgumentNullException(nameof(source));
case ICollection collection:
return collection.Count;
case IReadOnlyCollection collection:
return collection.Count;
default:
return null;
}
}
static int CountUpTo(this IEnumerable source, int max)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (max < 0) throw new ArgumentOutOfRangeException(nameof(max), "The maximum count argument cannot be negative.");
var count = 0;
using (var e = source.GetEnumerator())
{
while (count < max && e.MoveNext())
{
count++;
}
}
return count;
}
#endregion
}
}