Except has similar effect to Distinct?

后端 未结 3 567
说谎
说谎 2020-11-27 07:26

I just discovered that Except() will remove all elements in the second list from the first, but it also has the effect that it makes all elements in the returne

3条回答
  •  无人及你
    2020-11-27 07:59

    You wrote:

    Simple way around I am using is Where(v => !secondList.Contains(v))

    When you do this, there is still Distict done with secondList.

    For example:

    var firstStrings = new [] { "1", null, null, null, "3", "3" };
    var secondStrings = new [] { "1", "1", "1", null, null, "4" };
    var resultStrings = firstStrings.Where(v => !secondStrings.Contains(v)); // 3, 3  
    

    I created an extension method to have no distinct at all. Examle of usage:

    var result2Strings = firstStrings.ExceptAll(secondStrings).ToList(); // null, 3, 3
    

    This is what it does:

    enter image description here

    This is the source:

    public static IEnumerable ExceptAll(
        this IEnumerable first,
        IEnumerable second)
    {
        // Do not call reuse the overload method because that is a slower imlementation
        if (first == null) { throw new ArgumentNullException("first"); }
        if (second == null) { throw new ArgumentNullException("second"); }
    
        var secondList = second.ToList();
        return first.Where(s => !secondList.Remove(s));
    }
    
    public static IEnumerable ExceptAll(
        this IEnumerable first,
        IEnumerable second,
        IEqualityComparer comparer)
    {
        if (first == null) { throw new ArgumentNullException("first"); }
        if (second == null) { throw new ArgumentNullException("second"); }
        var comparerUsed = comparer ?? EqualityComparer.Default;
    
        var secondList = second.ToList();
        foreach (var item in first)
        {
            if (secondList.Contains(item, comparerUsed))
            {
                secondList.Remove(item);
            }
            else
            {
                yield return item;
            }
        }
    }
    

    Edit: A faster implemetation, based on the comment of DigEmAll

    public static IEnumerable ExceptAll(
            this IEnumerable first,
            IEnumerable second)
    {
        return ExceptAll(first, second, null);
    }
    
    public static IEnumerable ExceptAll(
        this IEnumerable first,
        IEnumerable second,
        IEqualityComparer comparer)
    {
        if (first == null) { throw new ArgumentNullException("first"); }
        if (second == null) { throw new ArgumentNullException("second"); }
    
    
        var secondCounts = new Dictionary(comparer ?? EqualityComparer.Default);
        int count;
        int nullCount = 0;
    
        // Count the values from second
        foreach (var item in second)
        {
            if (item == null)
            {
                nullCount++;
            }
            else
            {
                if (secondCounts.TryGetValue(item, out count))
                {
                    secondCounts[item] = count + 1;
                }
                else
                {
                    secondCounts.Add(item, 1);
                } 
            }
        }
    
        // Yield the values from first
        foreach (var item in first)
        {
            if (item == null)
            {
                nullCount--;
                if (nullCount < 0)
                {
                    yield return item;
                } 
            }
            else
            {
                if (secondCounts.TryGetValue(item, out count))
                {
                    if (count == 0)
                    {
                        secondCounts.Remove(item);
                        yield return item;
                    }
                    else
                    {
                        secondCounts[item] = count - 1;
                    }
                }
                else
                {
                    yield return item;
                }
            }
        }
    }
    

    More info on my blog (also variant for Intersect and Union)

提交回复
热议问题