3

我如何比较 2 个列表并根据具体属性有不匹配的项目

public partial class Cable : StateObject
{            
    public int Id { get; set; }
    public int CablePropertyId { get; set; }
    public int Item { get; set; }
    public int TagNo { get; set; }
    public string GeneralFormat { get; set; }
    public string EndString { get; set; }
    public string CableRevision { get; set; }         
}

如果我使用,我想根据 CablePropertyId、TagNo 和 CableRevision 完成比较

var diffCables = sourceCables.Except(destinationCables).ToList();

整个属性相互比较。我怎样才能做到这一点?

4

6 回答 6

4

使用带有自定义 EqualityComparer 的 Linq except 方法。

http://msdn.microsoft.com/en-us/library/bb336390(v=vs.110).aspx

class CableComparer : IEqualityComparer<Cable>
{
    public bool Equals(Cable x, Cable y)
    {
        return (x.CablePropertyId == y.CablePropertyId && ...);
    }

    public int GetHashCode(Cable x) // If you won't create a valid GetHashCode based on values you compare on, Linq won't work properly
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + x.CablePropertyID;
            hash = hash * 23 + ...
        }
        return hash;
    }
}

var diffCables = sourceCables.Except(destinationCables, new CableComparer());

此外,ToList()对结果的操作并不是真正必要的。大多数情况下,您可以直接对 Linq 查询的结果进行操作,而IEnumerable无需指定确切的类型;这样您就不会在不必要的ToList()操作上浪费性能。

顺便说一句,其他几个人提出了使用简单 lambda 的基于 Where 的查询。这样的解决方案更易于阅读(在我看来),但优化程度也较低:它强制进行 n^2 检查,而 IEqualityComparer 允许 Linq 由于GetHashCode()方法而更加优化。这是关于 GetHashCode 重要性的一个很好的答案,这是一个关于编写GetHashCode()override的很好的指南。

于 2013-11-05T13:36:03.263 回答
1

您可以像这样创建自己的IEqualityComparer<Cable>

public class CableComparer : IEqualityComparer<Cable>
{
    public bool Equals(Cable x, Cable y)
    {
        return x.CablePropertyId == y.CablePropertyId &&
               x.TagNo == y.TagNo &&
               x.CableRevision == y.CableRevision;
    }

    // If Equals() returns true for a pair of objects  
    // then GetHashCode() must return the same value for these objects. 
    public int GetHashCode(Cable x)
    {
        return x.CablePropertyId ^ 
               x.TagNo.GetHashCode() ^ 
               x.CableRevision.GetHashCode();
    }
}

然后使用这个重载Except

var comparer = new CableComparer();
var diffCables = sourceCables.Except(destinationCables, comparer).ToList();

或者,MoreLINQ 库(也可在 NuGet 上使用)提供了一种方便的ExceptBy方法:

var diffCables = sourceCables.ExceptBy(
        destinationCables, 
        x => new { 
            x.CablePropertyId, 
            x.TagNo,
            x.CableRevision
        })
    .ToList();
于 2013-11-05T13:37:54.033 回答
0

Cable如果您将始终以这种方式比较此对象,则可以覆盖 Equals 和 GetHashCode 方法。

否则,您可以编写自定义比较器并使用 .Except 的重载

List.Except 方法

于 2013-11-05T13:38:17.573 回答
0

如果您将 LINQ 与 一起使用IQueryable<>,则可能有解决方案Where()

var destinationCablesAnon = destinationCables.Select(a=>new {a.CablePropertyId, a.TagNo ,a.CableRevision}); // add ToArray() if use IEnumerable<>

var diffCables  = sourceCables.Where(a=>!destinationCables.Contains(new {a.CablePropertyId, a.TagNo ,a.CableRevision})).ToList();
于 2013-11-05T13:39:54.060 回答
0

本质上,当您想比较自己的类型时,您需要描述它们如何相互比较/不同。Linq 不知道你的Cable类中的哪些属性是不同的,对吧?

因此,您构建了一个比较器,该比较器通常可用于比较两种类型。

在这种情况下,有两种Cable情况:

class CableComparer : IEqualityComparer<Cable>
{

    public bool Equals(Cable c1, Cable c2)//these represent any two cables.
    {
        if (c1.Height == c2.Height && ...)
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    public int GetHashCode(Cable c)
    {
        //this will work if each ID is unique
        return c.Id.GetHashCode();
        //otherwise you do this:
        //return (c.Id ^ c. CablePropertyId).GetHashCode();
    }
}

然后:

IEnumerable<Cable> except =
            sourceCables.Except(destinationCables, new CableComparer());
于 2013-11-05T13:40:05.833 回答
0

我认为你可以使用这样的东西:

sourceCables.Where(sc => !destinationCables.Any(dc => dc.CablePropertyId == sc.CablePropertyId && ...));
于 2013-11-05T13:40:07.147 回答