Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] DistinctBy去重存在问题 #77

Closed
li-zheng-hao opened this issue Dec 16, 2022 · 2 comments
Closed

[BUG] DistinctBy去重存在问题 #77

li-zheng-hao opened this issue Dec 16, 2022 · 2 comments
Labels

Comments

@li-zheng-hao
Copy link

IEnumerable<int> arr = new List<int>() { 1, 2, 3 };

arr=arr.DistinctByEx(it => it);
arr.Count();
// 迭代无法获取到值
foreach (var i in arr)
{
    Console.Out.WriteLine("i={0}", i);
}
public static class Test
{
    public static IEnumerable<TSource> DistinctByEx<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector)
    {
        HashSet<TKey> hash = new HashSet<TKey>();
        return source.Where<TSource>((Func<TSource, bool>) (p => hash.Add(keySelector(p))));
    }

}

使用了Count之后无法遍历集合,调试发现在Count内部调用了where的条件判断:

image

导致foreach遍历时迭代器再次判断where条件时HashSet内部已经有值

image

建议替换成System.Linq内的官方写法,实测没有问题

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
{
    if (source is null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
    }
    if (keySelector is null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keySelector);
    }

    return DistinctByIterator(source, keySelector, comparer);
}

private static IEnumerable<TSource> DistinctByIterator<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
{
    using IEnumerator<TSource> enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {
        var set = new HashSet<TKey>(DefaultInternalSetCapacity, comparer);
        do
        {
            TSource element = enumerator.Current;
            if (set.Add(keySelector(element)))
            {
                yield return element;
            }
        }
        while (enumerator.MoveNext());
    }
}
@li-zheng-hao
Copy link
Author

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
            Func<TSource, TKey> keySelector)
{
    return source.DistinctBy(keySelector, null);
}

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));

    return _(); IEnumerable<TSource> _()
    {
        var knownKeys = new HashSet<TKey>(comparer);
        foreach (var element in source)
        {
            if (knownKeys.Add(keySelector(element)))
                yield return element;
        }
    }
}

这种写法也可以

ldqk added a commit that referenced this issue Dec 16, 2022
@ldqk
Copy link
Owner

ldqk commented Dec 16, 2022

已修正

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants