using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; namespace VCommon.Collections { public static class EnumerableExtensionMethod { /// 按提供的条件以及变换方法叠加序列 /// 序列元素类型 /// 分组类型 /// 序列 /// 叠加条件 /// 分组创建方法,提供当前元素 /// 分组叠加方法,提供分组和当前元素 public static TStackedGroup[] Stack(this IEnumerable sequence, Func groupingCondition, Func createStackGroup, Action addToGroup) where TStackedGroup : class { var list = new List(); TStackedGroup lasStackedGroup = null; foreach (var item in sequence) { var toGroup = groupingCondition(item); if (null != lasStackedGroup && toGroup) { addToGroup(lasStackedGroup, item); } else if (toGroup) { lasStackedGroup = createStackGroup(item); list.Add(lasStackedGroup); } else { lasStackedGroup = null; list.Add(createStackGroup(item)); } } return list.ToArray(); } /// /// 将序列中连续且符合条件的元素,保留第一个其余移除 /// /// 序列元素类型 /// 序列 /// 移除条件 public static T[] StackSequence(this IEnumerable sequence, Func stackCondition) where T : class { return sequence.Stack(stackCondition, p => p, (a, b) => { }); } public class Group { private readonly List _elements = new List(); public TElement[] Elements => _elements.ToArray(); public Group(TKey key) => Key = key; public void Add(TElement element) => _elements.Add(element); public TKey Key { get; } } public static Group[] GroupContiguous(this TElement[] sequence, Func keySelector) => GroupContiguous(sequence, keySelector, EqualityComparer.Default); public static Group[] GroupContiguous(this TElement[] sequence, Func keySelector, IEqualityComparer comparer) { var result = new List>(); Group group = null; foreach (var element in sequence) { var key = keySelector(element); if (null == group || false == comparer.Equals(group.Key, key)) { group = new Group(key); result.Add(group); group.Add(element); } else { group.Add(element); } } return result.ToArray(); } /// 包裹泛型IEnumerable实例, 避免可能的数组实例造成EF动态过滤失败 public static IEnumerable WrapEnumerable(this IEnumerable source) => new EnumerableWrapper(source); private class EnumerableWrapper : IEnumerable { private readonly IEnumerable _underlyingInstance; public EnumerableWrapper(IEnumerable underlyingInstance) => _underlyingInstance = underlyingInstance; IEnumerator IEnumerable.GetEnumerator() => _underlyingInstance.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _underlyingInstance.GetEnumerator(); } //public static HashSet ToHashSet(this IEnumerable source) => new HashSet(source); public static ConcurrentDictionary ToConcurrentDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer = null) { //REF: stackoverflow.com/a/27064366/2430943 with MODIFY if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); var d = comparer == null ? new ConcurrentDictionary() : new ConcurrentDictionary(comparer); foreach (var element in source) if (false == d.TryAdd(keySelector(element), elementSelector(element))) throw new ArgumentException("KeyDuplicated"); return d; } } }