using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; 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; } } } } }