EnumerableExtensionMethod.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. namespace VCommon.Collections
  6. {
  7. public static class EnumerableExtensionMethod
  8. {
  9. /// <summary> 按提供的条件以及变换方法叠加序列 </summary>
  10. /// <typeparam name="TInput">序列元素类型</typeparam>
  11. /// <typeparam name="TStackedGroup">分组类型</typeparam>
  12. /// <param name="sequence">序列</param>
  13. /// <param name="groupingCondition">叠加条件</param>
  14. /// <param name="createStackGroup">分组创建方法,提供当前元素</param>
  15. /// <param name="addToGroup">分组叠加方法,提供分组和当前元素</param>
  16. public static TStackedGroup[] Stack<TInput, TStackedGroup>(this IEnumerable<TInput> sequence, Func<TInput, bool> groupingCondition, Func<TInput, TStackedGroup> createStackGroup, Action<TStackedGroup, TInput> addToGroup) where TStackedGroup : class
  17. {
  18. var list = new List<TStackedGroup>();
  19. TStackedGroup lasStackedGroup = null;
  20. foreach (var item in sequence)
  21. {
  22. var toGroup = groupingCondition(item);
  23. if (null != lasStackedGroup && toGroup)
  24. {
  25. addToGroup(lasStackedGroup, item);
  26. }
  27. else if (toGroup)
  28. {
  29. lasStackedGroup = createStackGroup(item);
  30. list.Add(lasStackedGroup);
  31. }
  32. else
  33. {
  34. lasStackedGroup = null;
  35. list.Add(createStackGroup(item));
  36. }
  37. }
  38. return list.ToArray();
  39. }
  40. /// <summary>
  41. /// 将序列中连续且符合条件的元素,保留第一个其余移除
  42. /// </summary>
  43. /// <typeparam name="T">序列元素类型</typeparam>
  44. /// <param name="sequence">序列</param>
  45. /// <param name="stackCondition">移除条件</param>
  46. public static T[] StackSequence<T>(this IEnumerable<T> sequence, Func<T, bool> stackCondition) where T : class
  47. {
  48. return sequence.Stack(stackCondition, p => p, (a, b) => { });
  49. }
  50. public class Group<TKey, TElement>
  51. {
  52. private readonly List<TElement> _elements = new List<TElement>();
  53. public TElement[] Elements => _elements.ToArray();
  54. public Group(TKey key) => Key = key;
  55. public void Add(TElement element) => _elements.Add(element);
  56. public TKey Key { get; }
  57. }
  58. public static Group<TKey, TElement>[] GroupContiguous<TElement, TKey>(this TElement[] sequence, Func<TElement, TKey> keySelector) => GroupContiguous(sequence, keySelector, EqualityComparer<TKey>.Default);
  59. public static Group<TKey, TElement>[] GroupContiguous<TElement, TKey>(this TElement[] sequence, Func<TElement, TKey> keySelector, IEqualityComparer<TKey> comparer)
  60. {
  61. var result = new List<Group<TKey, TElement>>();
  62. Group<TKey, TElement> group = null;
  63. foreach (var element in sequence)
  64. {
  65. var key = keySelector(element);
  66. if (null == group || false == comparer.Equals(group.Key, key))
  67. {
  68. group = new Group<TKey, TElement>(key);
  69. result.Add(group);
  70. group.Add(element);
  71. }
  72. else
  73. {
  74. group.Add(element);
  75. }
  76. }
  77. return result.ToArray();
  78. }
  79. /// <summary> 包裹泛型IEnumerable实例, 避免可能的数组实例造成EF动态过滤失败 </summary>
  80. public static IEnumerable<T> WrapEnumerable<T>(this IEnumerable<T> source) => new EnumerableWrapper<T>(source);
  81. private class EnumerableWrapper<T> : IEnumerable<T>
  82. {
  83. private readonly IEnumerable<T> _underlyingInstance;
  84. public EnumerableWrapper(IEnumerable<T> underlyingInstance) => _underlyingInstance = underlyingInstance;
  85. IEnumerator<T> IEnumerable<T>.GetEnumerator() => _underlyingInstance.GetEnumerator();
  86. IEnumerator IEnumerable.GetEnumerator() => _underlyingInstance.GetEnumerator();
  87. }
  88. public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) => new HashSet<T>(source);
  89. public static ConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer = null)
  90. {
  91. //REF: stackoverflow.com/a/27064366/2430943 with MODIFY
  92. if (source == null) throw new ArgumentNullException(nameof(source));
  93. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  94. if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector));
  95. var d = comparer == null
  96. ? new ConcurrentDictionary<TKey, TElement>()
  97. : new ConcurrentDictionary<TKey, TElement>(comparer);
  98. foreach (var element in source)
  99. if (false == d.TryAdd(keySelector(element), elementSelector(element)))
  100. throw new ArgumentException("KeyDuplicated");
  101. return d;
  102. }
  103. }
  104. }