using System.Collections.Generic; namespace System.Linq { public static partial class EnumerableEx { /// /// Returns elements with a distinct key value by using the default equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Sequence that contains the elements from the source sequence with distinct key values. public static IEnumerable Distinct(this IEnumerable source, Func keySelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } return source.Distinct_(keySelector, EqualityComparer.Default); } /// /// Returns elements with a distinct key value by using the specified equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Comparer used to compare key values. /// Sequence that contains the elements from the source sequence with distinct key values. public static IEnumerable Distinct(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } return source.Distinct_(keySelector, comparer); } private static IEnumerable Distinct_(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { var set = new HashSet(comparer); foreach (var item in source) { var key = keySelector(item); if (set.Add(key)) { yield return item; } } } /// /// Returns consecutive distinct elements by using the default equality comparer to compare values. /// /// Source sequence element type. /// Source sequence. /// Sequence without adjacent non-distinct elements. public static IEnumerable DistinctUntilChanged(this IEnumerable source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } return source.DistinctUntilChanged_(x => x, EqualityComparer.Default); } /// /// Returns consecutive distinct elements by using the specified equality comparer to compare values. /// /// Source sequence element type. /// Source sequence. /// Comparer used to compare values. /// Sequence without adjacent non-distinct elements. public static IEnumerable DistinctUntilChanged(this IEnumerable source, IEqualityComparer comparer) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } return source.DistinctUntilChanged_(x => x, comparer); } /// /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Sequence without adjacent non-distinct elements. public static IEnumerable DistinctUntilChanged(this IEnumerable source, Func keySelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } return source.DistinctUntilChanged_(keySelector, EqualityComparer.Default); } /// /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Comparer used to compare key values. /// Sequence without adjacent non-distinct elements. public static IEnumerable DistinctUntilChanged(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } return source.DistinctUntilChanged_(keySelector, comparer); } private static IEnumerable DistinctUntilChanged_(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { var currentKey = default(TKey); var hasCurrentKey = false; foreach (var item in source) { var key = keySelector(item); var comparerEquals = false; if (hasCurrentKey) { comparerEquals = comparer.Equals(currentKey, key); } if (!hasCurrentKey || !comparerEquals) { hasCurrentKey = true; currentKey = key; yield return item; } } } } }