除了比较来自(第一)集合的项目

时间:2013-08-14 16:28:31

标签: c# linq-to-objects iequalitycomparer

我正在使用Enumerable.Except()从 activatedSerialNumbers 中排除 skipSerialNumbers 项目。

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

SamWithLicenseComparer 是:

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();
    }
}

因此,我得到了意想不到的价值,因为正如我发现的那样, activatedSerialNumbers 中的项目与自己进行比较。但逻辑是它们可能具有相同的名称,任务只是从 skipSerialNumbers 中删除所有项目。怎么做才能避免额外的比较?

2 个答案:

答案 0 :(得分:3)

Except是一个集合操作,因此结果将始终包含不同的值 例如,如果您执行{A,B,A,C}.Except({B,C}),则会获得{A},而不是{A, A}

你可以试试这个:

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

答案 1 :(得分:0)

如果您还想查看重复项,可以使用以下的变体:

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;
            }
        }
    }

现在你可以这样做:

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