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