除外比较调用(第一个)集合中的项

本文关键字:集合 第一个 比较 调用 | 更新日期: 2023-09-27 18:27:37

我正在使用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中删除所有项。如何避免额外的比较?

除外比较调用(第一个)集合中的项

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

如果您也想查看重复项,可以使用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;
            }
        }
    }

现在你可以这样做了:

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