根据特定属性比较两个列表

时间:2013-11-05 13:33:04

标签: c# linq

我如何比较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();

将整个属性相互比较。我怎么能这样做?

6 个答案:

答案 0 :(得分:4)

使用Linq除了使用自定义EqualityComparer的方法。

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的基于位置的查询。这种解决方案更容易阅读(在我看来),但它也不太优化:它强制n ^ 2检查,而IEqualityComparer允许Linq因GetHashCode()方法更优化。这是一个great answer on importance of GetHashCode,这里是great guide on writing GetHashCode() override

答案 1 :(得分: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();
    }
}

然后使用this overload of Except

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

或者,MoreLINQ library(也available on NuGet)提供了一种方便的ExceptBy方法:

var diffCables = sourceCables.ExceptBy(
        destinationCables, 
        x => new { 
            x.CablePropertyId, 
            x.TagNo,
            x.CableRevision
        })
    .ToList();

答案 2 :(得分:0)

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

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

List.Except Method

答案 3 :(得分: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();

答案 4 :(得分: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());

答案 5 :(得分:0)

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

sourceCables.Where(sc => !destinationCables.Any(dc => dc.CablePropertyId == sc.CablePropertyId && ...));