As slepic in his comment, I also wonder why you use and enumerator in the first and foreach
in the second place?
You can eliminate null
checks in the versions that call other overrides:
public static int DistinctCount<TSource>(this IEnumerable<TSource> source) => source?.DistinctCount((IEqualityComparer<TSource>)null) ?? throw new ArgumentNullException(nameof(source));
can be reduced to:
public static int DistinctCount<TSource>(this IEnumerable<TSource> source) => DistinctCount(source, (IEqualityComparer<TSource>)null);
And the other to:
public static int DistinctCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) => DistinctCount(source, predicate, null);
You could create a common counter method as:
private static int Count<TSource>(IEnumerable<TSource> source, Func<TSource, ISet<TSource>, bool> predicate, IEqualityComparer<TSource> comparer)
{
ISet<TSource> set = new HashSet<TSource>(comparer);
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
if (predicate(enumerator.Current, set))
{
checked
{
++num;
}
}
}
}
return num;
}
Called in the first as:
public static int DistinctCount<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
return Count(source, (o, set) => set.Add(o), comparer);
}
and in the latter as:
public static int DistinctCount<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate,
IEqualityComparer<TSource> comparer)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (predicate is null)
{
throw new ArgumentNullException(nameof(predicate));
}
return Count(source, (o, set) => predicate(o) && set.Add(o), comparer);
}
But do you really need num
? Couldn't you just return set.Count
?
By using ToHashSet<T>()
directly as show below I only find a minor loss in performance compared to your versions:
public static class ExtensionsReview
{
public static int DistinctCount<TSource>(this IEnumerable<TSource> source) => DistinctCount(source, (IEqualityComparer<TSource>)null);
public static int DistinctCount<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
return source.ToHashSet(comparer).Count;
}
public static int DistinctCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) => DistinctCount(source, predicate, null);
public static int DistinctCount<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate,
IEqualityComparer<TSource> comparer)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (predicate is null)
{
throw new ArgumentNullException(nameof(predicate));
}
return source.Where(predicate).ToHashSet(comparer).Count;
}
}