Enumerable.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. namespace MeloongCore.Extensions {
  5. public static class EnumerableExtensions {
  6. #region 去重
  7. /// <summary>
  8. /// 通过比较器进行去重。
  9. /// 该方法的效率较低,建议仅在小型列表上使用,或换用 DistinctBy。
  10. /// </summary>
  11. public static IEnumerable<T> Distinct<T>(this IList<T> list, Func<T, T, bool> comparer) {
  12. for (int i = 0; i < list.Count; i++) {
  13. if (!list.Skip(i + 1).Any(item => comparer(list[i], item))) yield return list[i];
  14. }
  15. }
  16. /// <summary>
  17. /// 按对象的指定值去重。
  18. /// </summary>
  19. public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> selector) {
  20. var seen = new HashSet<TKey>();
  21. foreach (var element in source) {
  22. if (seen.Add(selector(element))) yield return element;
  23. }
  24. }
  25. #endregion
  26. #region 取最大、最小值
  27. /// <summary>
  28. /// 选择所有最大值对应的对象。
  29. /// 若没有元素则返回空列表。
  30. /// </summary>
  31. public static List<T> MaxByAll<T, C>(this IEnumerable<T> source, Func<T, C> selector) where C : IComparable<C> {
  32. var results = new List<T>();
  33. using (var enumerator = source.GetEnumerator()) {
  34. if (!enumerator.MoveNext()) return results;
  35. T maxItem = enumerator.Current;
  36. C maxValue = selector(maxItem);
  37. results.Add(maxItem);
  38. while (enumerator.MoveNext()) {
  39. T currentItem = enumerator.Current;
  40. C currentValue = selector(currentItem);
  41. int comparisonResult = currentValue.CompareTo(maxValue);
  42. if (comparisonResult > 0) {
  43. maxValue = currentValue;
  44. results.Clear();
  45. results.Add(currentItem);
  46. } else if (comparisonResult == 0) {
  47. results.Add(currentItem);
  48. }
  49. }
  50. }
  51. return results;
  52. }
  53. /// <summary>
  54. /// 选择所有最小值对应的对象。
  55. /// 若没有元素则返回空列表。
  56. /// </summary>
  57. public static List<T> MinByAll<T, C>(this IEnumerable<T> source, Func<T, C> selector) where C : IComparable<C> {
  58. var results = new List<T>();
  59. using (var enumerator = source.GetEnumerator()) {
  60. if (!enumerator.MoveNext()) return results;
  61. T minItem = enumerator.Current;
  62. C minValue = selector(minItem);
  63. results.Add(minItem);
  64. while (enumerator.MoveNext()) {
  65. T currentItem = enumerator.Current;
  66. C currentValue = selector(currentItem);
  67. int comparisonResult = currentValue.CompareTo(minValue);
  68. if (comparisonResult < 0) {
  69. minValue = currentValue;
  70. results.Clear();
  71. results.Add(currentItem);
  72. } else if (comparisonResult == 0) {
  73. results.Add(currentItem);
  74. }
  75. }
  76. }
  77. return results;
  78. }
  79. /// <summary>
  80. /// 选择最大值对应的对象。
  81. /// 若没有元素则返回 Nothing。
  82. /// </summary>
  83. public static T MaxBy<T, C>(this IEnumerable<T> source, Func<T, C> selector) where C : IComparable<C> {
  84. using (var enumerator = source.GetEnumerator()) {
  85. if (!enumerator.MoveNext()) return default;
  86. T maxItem = enumerator.Current;
  87. C maxValue = selector(maxItem);
  88. while (enumerator.MoveNext()) {
  89. C value = selector(enumerator.Current);
  90. if (value.CompareTo(maxValue) <= 0) continue;
  91. maxItem = enumerator.Current;
  92. maxValue = value;
  93. }
  94. return maxItem;
  95. }
  96. }
  97. /// <summary>
  98. /// 选择最小值对应的对象。
  99. /// 若没有元素则返回 Nothing。
  100. /// </summary>
  101. public static T MinBy<T, C>(this IEnumerable<T> List, Func<T, C> Selector) where C : IComparable<C> {
  102. using (var enumerator = List.GetEnumerator()) {
  103. if (!enumerator.MoveNext()) { return default; }
  104. T minItem = enumerator.Current;
  105. C minValue = Selector(minItem);
  106. while (enumerator.MoveNext()) {
  107. C value = Selector(enumerator.Current);
  108. if (value.CompareTo(minValue) >= 0) { continue; }
  109. minItem = enumerator.Current;
  110. minValue = value;
  111. }
  112. return minItem;
  113. }
  114. }
  115. #endregion
  116. /// <summary>
  117. /// 判断集合是否有且仅有一个元素。
  118. /// </summary>
  119. public static bool IsSingle<T>(this IEnumerable<T> source) {
  120. if (source == null) return false;
  121. if (source is IList<T> list) return list.Count == 1;
  122. using (var enumerator = source.GetEnumerator()) {
  123. if (!enumerator.MoveNext()) return false;
  124. if (enumerator.MoveNext()) return false;
  125. return true;
  126. }
  127. }
  128. /// <summary>
  129. /// 对集合的每个元素执行指定操作。
  130. /// </summary>
  131. public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action) {
  132. foreach (T item in source) action(item);
  133. return source;
  134. }
  135. }
  136. }