Problem
I’m sure there’s an easy LINQ query for this, but I’m not sure how to do it.
Given this piece of code:
class Program
{
static void Main(string[] args)
{
List<Person> peopleList1 = new List<Person>();
peopleList1.Add(new Person() { ID = 1 });
peopleList1.Add(new Person() { ID = 2 });
peopleList1.Add(new Person() { ID = 3 });
List<Person> peopleList2 = new List<Person>();
peopleList2.Add(new Person() { ID = 1 });
peopleList2.Add(new Person() { ID = 2 });
peopleList2.Add(new Person() { ID = 3 });
peopleList2.Add(new Person() { ID = 4 });
peopleList2.Add(new Person() { ID = 5 });
}
}
class Person
{
public int ID { get; set; }
}
I’d like to use LINQ to get a list of all the people in peopleList2 who aren’t in peopleList1.
This example should provide me with two individuals. (IDs = 4 and 5)
Asked by JSprang
Solution #1
The following LINQ expression can be used to solve this problem:
var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
Another approach to express this using LINQ that some developers find more readable:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
Answered by Klaus Byskov Pedersen
Solution #2
You can also use: if you want to overcome the equality of people.
peopleList2.Except(peopleList1)
Because it can put the second list into a hashtable, Except should be substantially faster than the Where(…Any) option. Where(…Any) has an O(peopleList1.Count * peopleList2.Count) runtime, whereas HashSetT> versions (nearly) have an O(peopleList1.Count + peopleList2.Count) runtime.
Except implicitly removes duplicates. That shouldn’t affect your case, but might be an issue for similar cases.
If you want fast code but don’t want to override the equality, you can use the following syntax:
var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID));
var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));
Duplicates are not removed with this variant.
Answered by CodesInChaos
Solution #3
Alternatively, if you want it without the negation:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
Essentially, it states to obtain all from peopleList2, where all of the ids in peopleList1 differ from the id in peoplesList2.
A little different method from the standard response:)
Answered by user1271080
Solution #4
Because all of the previous solutions employed fluid syntax, here is a query expression syntax solution for those who are interested:
var peopleDifference =
from person2 in peopleList2
where !(
from person1 in peopleList1
select person1.ID
).Contains(person2.ID)
select person2;
Even though it would most certainly be optimum for Lists, I believe it is distinct enough from the answers offered to be of interest to some. This would absolutely be the way to go for tables with indexed IDs.
Answered by Michael Goldshteyn
Solution #5
Although I’m a little late to the game, here’s an excellent solution that’s also Linq to SQL compatible:
List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };
List<string> inList1ButNotList2 = (from o in list1
join p in list2 on o equals p into t
from od in t.DefaultIfEmpty()
where od == null
select o).ToList<string>();
List<string> inList2ButNotList1 = (from o in list2
join p in list1 on o equals p into t
from od in t.DefaultIfEmpty()
where od == null
select o).ToList<string>();
List<string> inBoth = (from o in list1
join p in list2 on o equals p into t
from od in t.DefaultIfEmpty()
where od != null
select od).ToList<string>();
Kudos to http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C
Answered by Richard Ockerby
Post is based on https://stackoverflow.com/questions/3944803/use-linq-to-get-items-in-one-list-that-are-not-in-another-list