DistinctUntilChanged.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. namespace System.Linq
  6. {
  7. public static partial class EnumerableEx
  8. {
  9. /// <summary>
  10. /// Returns consecutive distinct elements by using the default equality comparer to compare values.
  11. /// </summary>
  12. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  13. /// <param name="source">Source sequence.</param>
  14. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  15. public static IEnumerable<TSource> DistinctUntilChanged<TSource>(this IEnumerable<TSource> source)
  16. {
  17. if (source == null)
  18. throw new ArgumentNullException(nameof(source));
  19. return DistinctUntilChangedCore(source, x => x, EqualityComparer<TSource>.Default);
  20. }
  21. /// <summary>
  22. /// Returns consecutive distinct elements by using the specified equality comparer to compare values.
  23. /// </summary>
  24. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  25. /// <param name="source">Source sequence.</param>
  26. /// <param name="comparer">Comparer used to compare values.</param>
  27. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  28. public static IEnumerable<TSource> DistinctUntilChanged<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  29. {
  30. if (source == null)
  31. throw new ArgumentNullException(nameof(source));
  32. if (comparer == null)
  33. throw new ArgumentNullException(nameof(comparer));
  34. return DistinctUntilChangedCore(source, x => x, comparer);
  35. }
  36. /// <summary>
  37. /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
  38. /// </summary>
  39. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  40. /// <typeparam name="TKey">Key type.</typeparam>
  41. /// <param name="source">Source sequence.</param>
  42. /// <param name="keySelector">Key selector.</param>
  43. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  44. public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  45. {
  46. if (source == null)
  47. throw new ArgumentNullException(nameof(source));
  48. if (keySelector == null)
  49. throw new ArgumentNullException(nameof(keySelector));
  50. return DistinctUntilChangedCore(source, keySelector, EqualityComparer<TKey>.Default);
  51. }
  52. /// <summary>
  53. /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
  54. /// </summary>
  55. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  56. /// <typeparam name="TKey">Key type.</typeparam>
  57. /// <param name="source">Source sequence.</param>
  58. /// <param name="keySelector">Key selector.</param>
  59. /// <param name="comparer">Comparer used to compare key values.</param>
  60. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  61. public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  62. {
  63. if (source == null)
  64. throw new ArgumentNullException(nameof(source));
  65. if (keySelector == null)
  66. throw new ArgumentNullException(nameof(keySelector));
  67. if (comparer == null)
  68. throw new ArgumentNullException(nameof(comparer));
  69. return DistinctUntilChangedCore(source, keySelector, comparer);
  70. }
  71. private static IEnumerable<TSource> DistinctUntilChangedCore<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  72. {
  73. var currentKey = default(TKey)!;
  74. var hasCurrentKey = false;
  75. foreach (var item in source)
  76. {
  77. var key = keySelector(item);
  78. var comparerEquals = false;
  79. if (hasCurrentKey)
  80. {
  81. comparerEquals = comparer.Equals(currentKey, key);
  82. }
  83. if (!hasCurrentKey || !comparerEquals)
  84. {
  85. hasCurrentKey = true;
  86. currentKey = key;
  87. yield return item;
  88. }
  89. }
  90. }
  91. }
  92. }