I am trying to compare two list of same type using multiple properties of that type.
For example,
I have a class named Details
public class Details
{
public int id;
public string symbol;
public string code;
}
I have below two lists:
List<Details> list1 = new List<Details>();
List<Details> list2 = new List<Details>();
list1.Add(new Details() { id=1,symbol="ANSI",code="NITE"});
list1.Add(new Details() { id = 1, symbol = "ANSI", code = "CALGO" });
list1.Add(new Details() { id = 1, symbol = "ANSI", code = "CANT" });
list1.Add(new Details() { id=2,symbol="ANSI",code="NITE"});
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CALGO" });
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CANT" });
list2.Add(new Details() { id = 1, symbol = "ANSI", code = "NITE" });
list2.Add(new Details() { id = 1, symbol = "ANSI", code = "CALGO" });
list2.Add(new Details() { id = 2, symbol = "ANSI", code = "NITE" });
I want only that data from List1 which has same id, symbol but different code.
So, in above scenario result will be as below.
list1.Add(new Details() { id = 1, symbol = "ANSI", code = "CANT" });
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CALGO" });
list1.Add(new Details() { id = 2, symbol = "ANSI", code = "CANT" });
It would be great if this can be achieved through Linq instead of using foreach.
I tried below but that's not correct.
var temp =list1.Where(x=>list2.Any(z=>x.id==z.id && string.Equals(x.symbol,z.symbol) && !string.Equals(x.code,z.code)));
It looks like you need rows to satisfy two conditions, not one, in order to make the output:
id
and symbol
, and id
, symbol
, and code
. Here is how to do that with LINQ directly:
var tmp = list1.Where(x=>
list2.Any(z=>x.id==z.id && x.symbol==z.symbol)
&& !list2.Any(z => x.id==z.id && x.symbol==z.symbol && x.code==z.code));
An alternative based on applying De Morgan's laws :
var tmp = list1.Where(x=>
list2.Any(z=>x.id==z.id && x.symbol==z.symbol)
&& list2.All(z => x.id!=z.id || x.symbol!=z.symbol || x.code!=z.code));
1) I would first override Equals
(and also GetHashCode
)
public class Details
{
public int id;
public string symbol;
public string code;
public override int GetHashCode()
{
return (id + symbol + code).GetHashCode();
}
public override bool Equals(object obj)
{
var other = obj as Details;
if (other == null) return false;
return id == other.id && symbol == other.symbol && code == other.code;
}
}
Then you can use Linq as
var result = list1.Except(list2).ToList();
It returns the result you expect...
2) Same result can also be obtained without changing the Details
object and by implementing a custom IEqualityComparer
public class DetailsComparer : IEqualityComparer<Details>
{
public bool Equals(Details x, Details y)
{
return x.id == y.id && x.symbol == y.symbol && x.code == y.code;
}
public int GetHashCode(Details obj)
{
return (obj.id + obj.symbol + obj.code).GetHashCode();
}
}
Then your linq would be
var result = list1.Except(list2, new DetailsComparer()).ToList();
Those ways are better than O(n*n) algorithms utilizing of Any
and All
of course, you can do compare like your code, but if you want your code are more structure you can override method Equals()
and Operator ==
:
public class Details
{
public int id;
public string symbol;
public string code;
public override bool Equals(System.Object obj)
{
if (obj == null) {
return false;
}
Details detail = obj as Details;
if ((System.Object) detail == null) {
return false;
}
return (id == detail.id) && (symbol == detail.symbol);
}
public bool Equals(other) {
return this.id == other.id && this.symbole == other.symbol;
}
public override int GetHashCode() {
return id ^ symbol.GetHashCode();
}
}
then you can compare two Detail object directly.
Do this:
public class DetailsComparer : IEqualityComparer<Details>
{
public bool Equals(Details x, Details y)
=> x.id == y.id && x.symbol == y.symbol && x.code == y.code;
public int GetHashCode(Details obj)
=> obj.code.GetHashCode();
}
And use wery simple this
var x = list1.Except(list2, new DetailsComparer());
result x:
1, ANSI, CANT
2, ANSI, CALGO
2, ANSI, CANT
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.