C# 查找并选择两个对象列表之间的特定更改

C# 查找并选择两个对象列表之间的特定更改,c#,list,object,properties,compare,C#,List,Object,Properties,Compare,我有两个对象T的列表。每个T都有唯一的键“T.key” 这将生成您的预期输出: List<T> list1 = new List<T> { new T { key = 1, a = 10, b = 10, c = 10 }, new T { key = 2, a = 10, b = 10, c = 10 }, new T { key = 3, a = 10, b = 10, c = 10 } }; List<T> list2 = new List<T

我有两个对象T的列表。每个T都有唯一的键“T.key”


这将生成您的预期输出:

 List<T> list1 = new List<T> { new T { key = 1, a = 10, b = 10, c = 10 }, new T { key = 2, a = 10, b = 10, c = 10 }, new T { key = 3, a = 10, b = 10, c = 10 } };
 List<T> list2 = new List<T> { new T { key = 1, a = 10, b = 10, c = 99 }, new T { key = 2, a = 11, b = 10, c = 10 }, new T { key = 4, a = 10, b = 10, c = 10 } };

 List<int> difference = new List<int>();

 foreach (var item2 in list2)
 {
     var item1 = list1.FirstOrDefault(i => i.key == item2.key);

     if (item1 != null)
     {
         if (item2.a == item1.a && item2.b == item1.b)
             continue;
     }           

     difference.Add(item2.key);
 }
List list1=newlist{new T{key=1,a=10,b=10,c=10},new T{key=2,a=10,b=10,c=10},new T{key=3,a=10,b=10,c=10};
List list2=新列表{new T{key=1,a=10,b=10,c=99},new T{key=2,a=11,b=10,c=10},new T{key=4,a=10,b=10,c=10};
列表差异=新列表();
foreach(列表2中的变量项2)
{
var item1=list1.FirstOrDefault(i=>i.key==item2.key);
if(item1!=null)
{
if(item2.a==item1.a&&item2.b==item1.b)
继续;
}           
差异。添加(项目2.键);
}

difference
包含
{2,4}

一个完整的示例,该示例生成预期的键:2和4

List<F> L1 = new List<F>{new F(1,10,10,10), new F(2,10,10,10), new F(3,10,10,10)};
List<F> L2 = new List<F>{new F(1,10,10,99), new F(2,11,10,10), new F(4,10,10,10)}; 

void Main() { // Client code. One call covers the biz logic (and sample output)
    // Must call Except on L2 with L1 as the arg for proper eval of biz logic
    foreach ( var item in L2.Except(L1, new CompareListsOfObjsF()) ) 
        Console.WriteLine("key: " + item.key);  
}

class F { // Quick, dirty sample POCO w/ constructor
    public int key, a, b, c; 
    public F(int mk, int ma, int mb, int mc) { key=mk; a=ma; b=mb; c=mc; }
} 

class CompareListsOfObjsF : IEqualityComparer<F> {
    // business-specific equality logic - notice that 'c' is not evaluated
    public bool Equals(F x, F y) {
        return  x.key == y.key && x.a == y.a && x.b == y.b;
    }
    // The logic will not work without a proper hash function:
    public int GetHashCode(F x) { unchecked { // Overflow is ok
            int h = 17 * 23 + x.key;
            h += h * 23 + x.a;
            h += h * 23 + x.b;
            return h; // c has to be left out for selection biz logic to work
      }
   } 
}
List L1=新列表{new F(1,10,10,10),new F(2,10,10,10),new F(3,10,10)};
列表L2=新列表{new F(1,10,10,99),new F(2,11,10,10),new F(4,10,10)};
void Main(){//客户端代码。一个调用涵盖了业务逻辑(和示例输出)
//为了正确评估业务逻辑,必须以L1为参数调用L2上的除外
foreach(L2.Except中的var项(L1,新的CompareListsOfObjsF())
Console.WriteLine(“key:+item.key”);
}
类{//快速、脏样POCO w/构造函数
公钥,a,b,c;
公共F(intmk,intma,intmb,intmc){key=mk;a=ma;b=mb;c=mc;}
} 
类compareListOfobJSF:IEqualityComparer{
//特定于业务的相等逻辑-请注意,未计算“c”
公共布尔等于(fx,fy){
返回x.key==y.key&&x.a==y.a&&x.b==y.b;
}
//如果没有适当的哈希函数,逻辑将无法工作:
public int GetHashCode(fx){unchecked{//溢出正常
int h=17*23+x.键;
h+=h*23+x.a;
h+=h*23+x.b;
return h;//c必须被省略,选择业务逻辑才能工作
}
} 
}
输出:

关键词:2

关键词:4


前半部分很直截了当,你问题的后半部分没有多大意义“不在两个列表中”是指“只在一个列表中”?我把“不在两个列表中”理解为“不在
L2
中”.是的,我认为两个输入列表的一些示例数据和您对输出的期望将极大地澄清所需内容。您的编辑使其非常清晰。很好。。。你打败了我。。。我认为这是最新问题的最佳答案。您可以添加,他还可以将
IEqualityComparer
构建到他的
F
类中。另外,
GetHashCode
应该返回键的hashcode,a和b异或在一起,或者沿着这些行返回。@Kevin:谢谢你的夸奖。我重新组织了示例并添加了一些注释。HashCode是一个完全的hack,目的是让编译器满意。它的实现对OP没有影响。如果OP需要一个功能良好的哈希代码,那么这是一个单独的问题。:-)但我确实同意,根据业务规则,POCO应该包含IEqualityComparer的实现。在任何情况下,片段都在那里,干净地分开,供OP随意使用。。。有一件事。。。我想补充一点,如果你想把IEquality comparer放在字典/哈希表等需要哈希代码的地方,它应该实现GetHashCode。@Kevin:Oops。。。我在玩散列,注意到我从Jon Skeet的一个著名答案中提取的散列函数产生了一个不正确的结果。起初我很困惑,但意识到Except函数必须在其实现中使用Dictionary/HashSet。因此,我们吸取了教训。总是以适当的方式进行。GetHashCode的一部分。返回值1的黑客刚好工作!很好。我想投赞成票,但我已经投了。既然你提到了这件事,我意识到我以前也遇到过这种情况,但已经有一段时间了。这就是为什么您必须向它传递一个
IEqualityComparer
,因为它需要
GetHashCode()
 List<T> list1 = new List<T> { new T { key = 1, a = 10, b = 10, c = 10 }, new T { key = 2, a = 10, b = 10, c = 10 }, new T { key = 3, a = 10, b = 10, c = 10 } };
 List<T> list2 = new List<T> { new T { key = 1, a = 10, b = 10, c = 99 }, new T { key = 2, a = 11, b = 10, c = 10 }, new T { key = 4, a = 10, b = 10, c = 10 } };

 List<int> difference = new List<int>();

 foreach (var item2 in list2)
 {
     var item1 = list1.FirstOrDefault(i => i.key == item2.key);

     if (item1 != null)
     {
         if (item2.a == item1.a && item2.b == item1.b)
             continue;
     }           

     difference.Add(item2.key);
 }
List<F> L1 = new List<F>{new F(1,10,10,10), new F(2,10,10,10), new F(3,10,10,10)};
List<F> L2 = new List<F>{new F(1,10,10,99), new F(2,11,10,10), new F(4,10,10,10)}; 

void Main() { // Client code. One call covers the biz logic (and sample output)
    // Must call Except on L2 with L1 as the arg for proper eval of biz logic
    foreach ( var item in L2.Except(L1, new CompareListsOfObjsF()) ) 
        Console.WriteLine("key: " + item.key);  
}

class F { // Quick, dirty sample POCO w/ constructor
    public int key, a, b, c; 
    public F(int mk, int ma, int mb, int mc) { key=mk; a=ma; b=mb; c=mc; }
} 

class CompareListsOfObjsF : IEqualityComparer<F> {
    // business-specific equality logic - notice that 'c' is not evaluated
    public bool Equals(F x, F y) {
        return  x.key == y.key && x.a == y.a && x.b == y.b;
    }
    // The logic will not work without a proper hash function:
    public int GetHashCode(F x) { unchecked { // Overflow is ok
            int h = 17 * 23 + x.key;
            h += h * 23 + x.a;
            h += h * 23 + x.b;
            return h; // c has to be left out for selection biz logic to work
      }
   } 
}