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 } }