Question

I'm using Enumerable.Except() to exclude skipSerialNumbers items from activatedSerialNumbers.

activatedSerialNumbers = activatedSerialNumbers
                    .Except(skipSerialNumbers, new SamWithLicenseComparer()).ToList();

SamWithLicenseComparer is:

internal class SamWithLicenseComparer : IEqualityComparer<SamWithLicense>
{
    public bool Equals(SamWithLicense x, SamWithLicense y)
    {
        if (ReferenceEquals(x, y)) 
            return true;

        if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
            return false;

        if(x.Name.ToLower() != y.Name.ToLower())
            return false;
        return true;
    }

    public int GetHashCode(SamWithLicense sam)
    {
        if (ReferenceEquals(sam, null)) 
            return 0;
        return sam.Name == null ? 0 : sam.Name.ToLower().GetHashCode();
    }
}

As a result I get unexpected value, because, as I found out, items from activatedSerialNumbers compare with themselves. But the logic is that they may have the same names, task is just remove all items from skipSerialNumbers. How to do that avoiding an extra comparison?

Was it helpful?

Solution

Except is a set operation so the result will contain always distinct values.
For example if you do {A,B,A,C}.Except({B,C}) you'll get {A}, not {A, A}.

You can try this:

var skipSesialNumbersSet = new HashSet<SamWithLicense>(skipSerialNumbers, new SamWithLicenseComparer());
activatedSerialNumbers = activatedSerialNumbers.Where(x => !skipSesialNumbersSet.Contains(x)).ToList();

OTHER TIPS

If you want to see the duplicates also, you can use this variant of Except:

public static IEnumerable<TSource> ExceptWithDuplicates<TSource>(
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second)
    {
        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<TSource> ExceptWithDuplicates<TSource>(
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second,
        IEqualityComparer<TSource> comparer)
    {
        if (first == null) { throw new ArgumentNullException("first"); }
        if (second == null) { throw new ArgumentNullException("second"); }
        var comparerUsed = comparer ?? EqualityComparer<TSource>.Default;

        var secondList = second.ToList();
        foreach (var item in first)
        {
            if (secondList.Contains(item, comparerUsed))
            {
                secondList.Remove(item);
            }
            else
            {
                yield return item;
            }
        }
    }

Now you can do this:

var first = new [] { 1, 1, 1, 2, 2, 2, 3, 3 };
var second = new[] { 1, 2, 2, 4 };

var withoutDuplicates = first.Except(second);  // 3 
var witDuplicates = first.ExceptWithDuplicates(second);  // 1, 1, 2, 3, 3 : Note that 1 and 2 are also in the list
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top