EnumerableExtensions.cs 6.0 KB

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