c#Linq-检查另一个列表中是否存在复合密钥

c#Linq-检查另一个列表中是否存在复合密钥,c#,linq,C#,Linq,我有一个错误列表,定义如下: List<Errors> test1 = new List<Errors>(); public class Errors { public int ID {get; set;} public int Occurrence {get; set;} //..... //..... } 您就快到了,只需在LINQ表达式中添加一个正确的条件: var test2NotInTest1 = listOfErrors.W

我有一个错误列表,定义如下:

List<Errors> test1 = new List<Errors>();

public class Errors
{
    public int ID {get; set;}
    public int Occurrence {get; set;}
    //.....
    //.....
}

您就快到了,只需在LINQ表达式中添加一个正确的条件:

var test2NotInTest1 = listOfErrors.Where(e => !listOfTasks.Any(t => t.ID == e.Id && t.Occurrence == e.Occurrence)).ToList();

您就快到了,只需在LINQ表达式中添加一个正确的条件:

var test2NotInTest1 = listOfErrors.Where(e => !listOfTasks.Any(t => t.ID == e.Id && t.Occurrence == e.Occurrence)).ToList();

只需使用and
&&
运算符并检查两个属性,而不是一个:

var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t1.ID == t2.ID && t1.Occurance == t2.Occurance);

只需使用and
&&
运算符并检查两个属性,而不是一个:

var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t1.ID == t2.ID && t1.Occurance == t2.Occurance);

有一个函数用于。。。除了

var test2NotInTest1 = test1.Except(test2);
如果没有,则需要为equal创建接口,如下所示:

var test2NotInTest1 = test1.Except(test2, new ErrorsComparer()); 


class ErrorsComparer : IEqualityComparer<Errors>
{
    public bool Equals(Errors x, Errors y)
    {
        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether the products' properties are equal.
        return x.ID == y.ID && x.Occurrence == y.Occurrence;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.
    public int GetHashCode(Errors e)
    {
        if (Object.ReferenceEquals(e, null)) return 0;

        int hashID = e.ID == null ? 0 : e.ID.GetHashCode();
        int hashO = e.Occurrence.GetHashCode();

        //Calculate the hash code for the product.
        return hashID ^ hashO;
    }
}
var test2NotInTest1=test1.Except(test2,newerrorscomparer());
类错误比较者:IEqualityComparer
{
公共布尔等于(错误x,错误y)
{
//检查比较对象是否引用相同的数据。
if(Object.ReferenceEquals(x,y))返回true;
//检查是否有任何比较对象为空。
if(Object.ReferenceEquals(x,null)| | Object.ReferenceEquals(y,null))
返回false;
//检查产品的属性是否相等。
返回x.ID==y.ID&&x.Occurrence==y.Occurrence;
}
//对于一对对象,If Equals()返回true
//然后GetHashCode()必须为这些对象返回相同的值。
public int GetHashCode(错误e)
{
if(Object.ReferenceEquals(e,null))返回0;
int hashID=e.ID==null?0:e.ID.GetHashCode();
int hashO=e.Occurrence.GetHashCode();
//计算产品的哈希代码。
返回hashID^hashO;
}
}

有一个函数用于。。。除了

var test2NotInTest1 = test1.Except(test2);
如果没有,则需要为equal创建接口,如下所示:

var test2NotInTest1 = test1.Except(test2, new ErrorsComparer()); 


class ErrorsComparer : IEqualityComparer<Errors>
{
    public bool Equals(Errors x, Errors y)
    {
        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether the products' properties are equal.
        return x.ID == y.ID && x.Occurrence == y.Occurrence;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.
    public int GetHashCode(Errors e)
    {
        if (Object.ReferenceEquals(e, null)) return 0;

        int hashID = e.ID == null ? 0 : e.ID.GetHashCode();
        int hashO = e.Occurrence.GetHashCode();

        //Calculate the hash code for the product.
        return hashID ^ hashO;
    }
}
var test2NotInTest1=test1.Except(test2,newerrorscomparer());
类错误比较者:IEqualityComparer
{
公共布尔等于(错误x,错误y)
{
//检查比较对象是否引用相同的数据。
if(Object.ReferenceEquals(x,y))返回true;
//检查是否有任何比较对象为空。
if(Object.ReferenceEquals(x,null)| | Object.ReferenceEquals(y,null))
返回false;
//检查产品的属性是否相等。
返回x.ID==y.ID&&x.Occurrence==y.Occurrence;
}
//对于一对对象,If Equals()返回true
//然后GetHashCode()必须为这些对象返回相同的值。
public int GetHashCode(错误e)
{
if(Object.ReferenceEquals(e,null))返回0;
int hashID=e.ID==null?0:e.ID.GetHashCode();
int hashO=e.Occurrence.GetHashCode();
//计算产品的哈希代码。
返回hashID^hashO;
}
}
For:要确定任务中是否存在来自错误的复合ID,

另一种方法是使用

For:确定来自错误的复合ID是否在任务中不存在,如示例中所示:
var test2NotInTest1=test2.Where(t2=>!test1.Any(t1=>t2.Contains(t1))

您可以使用HashSet“加速”搜索已分配的错误

var assignedErrors = tasks.Select(task => (task.Id, task.Occurrence)).ToHashSet();
var notAssignedErrors =
    errors.Where(error => assignedErrors.Contains((error.Id, error.Occurrence)) == false)
          .ToList();
或者创建自己的特定于域的扩展方法:

public static IEnumerable<Errors> NotAssignedIn(
    this IEnumerable<Errors> errors, 
    IEnumerable<Tasks> tasks)
{
    var assigned = new HashSet<(int Id, int Occurrence)>();

    foreach (var task in tasks)
    {
        assigned.Add((task.Id, task.Occurrence));
    }

    foreach (var error in errors)
    {
        if (assigned.Contains((error.Id, error.Occurrence)) == false)
        {
            yield return error;
        }            
    }
}
For:要确定任务中是否存在来自错误的复合ID,

另一种方法是使用

For:确定来自错误的复合ID是否在任务中不存在,如示例中所示:
var test2NotInTest1=test2.Where(t2=>!test1.Any(t1=>t2.Contains(t1))

您可以使用HashSet“加速”搜索已分配的错误

var assignedErrors = tasks.Select(task => (task.Id, task.Occurrence)).ToHashSet();
var notAssignedErrors =
    errors.Where(error => assignedErrors.Contains((error.Id, error.Occurrence)) == false)
          .ToList();
或者创建自己的特定于域的扩展方法:

public static IEnumerable<Errors> NotAssignedIn(
    this IEnumerable<Errors> errors, 
    IEnumerable<Tasks> tasks)
{
    var assigned = new HashSet<(int Id, int Occurrence)>();

    foreach (var task in tasks)
    {
        assigned.Add((task.Id, task.Occurrence));
    }

    foreach (var error in errors)
    {
        if (assigned.Contains((error.Id, error.Occurrence)) == false)
        {
            yield return error;
        }            
    }
}

它将比较哈希代码,而不是字段OPneeds@Fabjan你不认为有错误的理由吗?我不知道是什么让你认为有错误。。。好吧,这只是OP拥有的一个自定义类created@LCaraway它应该更快——它只需要为list1和list2计算一次散列,因此它应该在O(n1+n2)处运行——使用与嵌套循环相同的任何函数,将得到O(n1*n2)(其中nX是两个列表的len。)非常容易测试。上次我不得不这么做时,我看到了速度的提高。注意,如果您的列表很小(<100)请使用where方法),我担心这不会针对OP case编译,因为OP需要比较不同类型的列表
错误
任务
。它将比较hashcode,而不是OP字段needs@Fabjan你不认为有错误的理由吗,我不知道是什么让你认为有。。。好吧,这只是OP拥有的一个自定义类created@LCaraway它应该更快——它只需要为list1和list2计算一次散列,因此它应该在O(n1+n2)处运行——使用与嵌套循环相同的任何函数,将得到O(n1*n2)(其中nX是两个列表的len。)非常容易测试。上次我不得不这么做时,我看到了速度的提高。注意,如果您的列表很小(<100),请使用where方法),恐怕这不会针对OP案例进行编译,因为OP需要比较不同类型的
Errors
Tasks
的列表。仅供参考,通常类的名称是单数的(即
Task
Error
),除非它们是集合类型。然后这些类型的集合将具有复数名称(就像您在代码中所做的那样)。仅供参考,通常类具有单数名称(即
Task
Error
),除非它们是集合类型。然后这些类型的集合将具有复数名称(就像您在代码中所做的那样)。这不执行内部联接吗。我想他想要的是一个左侧连接,右侧为null的Except。@Hogan,为了确定列表中的复合ID是否存在于列表中,如果我正确理解OP,那么“存在于”应该是“join”——哇,我完全没有读到这个问题——我想他想要的是一个Except。很抱歉