Reputation: 1371
I have two lists
List1 Only two property. Cant use Dictionary since there might be duplicate keys. The combination of Property1 and Property2 is unique.
public class List1
{
public string Property1 { get; internal set; }
public string Property2 { get; internal set; }
}
public class List2
{
public string Property1 { get; internal set; }
public string Property2 { get; internal set; }
public string Property3 { get; internal set; }
}
List<List1> mylist1 = new List<List1>() {
new List1() {Property1="664",Property2="Ford" },
new List1() {Property1="665",Property2="Ford" },
new List1() {Property1="664",Property2="Toyota" },
};
List<List2> mylist2 = new List<List2>() {
new List2() {Property1="664",Property2="Ford" ,Property3="USA"},
new List2() {Property1="665",Property2="Ford" ,Property3="USA"},
new List2() {Property1="664",Property2="Toyota" ,Property3="USA"},
new List2() {Property1="666",Property2="Toyota" ,Property3="USA"},
};
I need to get the matching items in mylist1 and mylist2. The match should happen only on Property1 and Property2. Property3 in the mylist2 can be ignored during comparison.
Currently I use
var matchingCodes = mylist1.Where(l1 => mylist2.Any(l2 => (l2.Property1 == l1.Property1 && l2.Property2==l1.Property2))).ToList();
which works perfectly fine. But is there a better way/ fastest way to do this?
I can change List1 to any other Type. but not List2.
Upvotes: 4
Views: 4511
Reputation: 528
You are trying to do set
operations on your data lists in LINQ. There are four LINQ function calls that you can use to make the current code cleaner as well as succinct. These operations are:
The one you are looking for is Intersect which is
Returns the set of values found t be identical in two separate collections Source
Finally, if you are always going to use those specific properties to detect equality and/or uniqueness you will need to override Equals
for List1 and/or List2 classes. This would depend who is considered on the left hand of the Intersect (the variable before the .) and who is on the right hand of the Intersect (the variable passed into the function).
Here is a SO answer to how to override the Equals
function if you do not know how to do so. Coincidentally, it also has an Intersect
example.
Upvotes: 3
Reputation: 9467
The easiest way to do it in Linq which is relatively fast, or atleast faster than your approach is using Join
or GroupJoin
like so:
List<List1> matchingCodes = mylist1.GroupJoin(mylist2,
l1 => new { l1.Property1, l1.Property2 },// Define how the key from List1 looks like
l2 => new { l2.Property1, l2.Property2 },// Define how the key from List2 looks like
// Define what we select from the match between list1 and list2
(l1Item, l2Items) => l1Item).ToList();
Simplified, this creates two dictionaries which are then joined together.
GroupJoin
works better here as it gives you the item from List1 and all matching from list2.
A regular Join
would return the same item from List1 per match from List2.
See also Enumerable.GroupJoin (C# Reference)
Note this is the equivalent to @octavioccl's answer. Also this example assumes, the names of the properties from both classes are equal. If they arent you have to modifiy they keyselectors abit like so:
l1 => new { A=l1.Foo, B=l1.Bar},
l2 => new { A=l2.Herp, B=l2.Derp},
Upvotes: 3
Reputation: 39326
You could also do a join:
var query= from l in mylist1
join e in mylist2 on new {Property1=l.Property1,Property2=l.Property2} equals new {Property1=e.Property1,Property2=e.Property2}
select l;
Upvotes: 3
Reputation: 170
Both properties are strings so that you can just create a dictionary with a key the concatenation of those properties with a Value of the actual item.
So for each item in the other list you can just look up in the dictionary for the concatenation of their property, if there is a match, you compare with the item found
Upvotes: 0