使用LINQ获取一个List <>中的项目,这些项目不在另一个List <>中
我会假设有一个简单的LINQ查询来做到这一点,我只是不完全知道如何。 请参阅下面的代码片段,注释说明了我想要做的事情:
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 }); //I would like to perform a LINQ query to give me all //of the people in 'peopleList2' that are not in 'peopleList1' //this example should give me two people (ID = 4 & ID = 5) } } class Person { public int ID { get; set; } }
var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
如果你重写人的平等,那么你也可以使用:
peopleList2.Except(peopleList1)
Except
应该明显快于Where(...Any)
变体,因为它可以把第二个列表放入一个哈希表。 Where(...Any)
的运行时间为O(peopleList1.Count * peopleList2.Count)
而基于HashSet<T>
(几乎)的variables的运行时间为O(peopleList1.Count + peopleList2.Count)
。
Except
隐式删除重复。 这不应该影响你的情况,但可能是类似的情况下的问题。
或者,如果你想快速的代码,但不想重写相等:
var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID)); var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));
此变体不会删除重复项。
由于迄今为止所有解决scheme都使用stream畅的语法,因此对于感兴趣的用户来说,这是查询expression式语法的解决scheme:
var peopleDifference = from person2 in peopleList2 where !( from person1 in peopleList1 select person1.ID ).Contains(person2.ID) select person2;
我认为这个答案与一些有兴趣的答案是不一样的,甚至认为它对列表来说可能是最不理想的。 现在,对于带有索引ID的表格,这肯定是要走的路。
或者,如果你想要没有否定:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
基本上说,从peopleList2中获取所有人,其中peopleList1中的所有id与peoplesList2中的id不同。
只是从接受的答案一点点不同的方法:)
比赛晚了,但是Linq兼容SQL的一个很好的解决scheme是:
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>();
荣誉http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C
该Enumerable扩展允许您定义要排除的项目列表以及用于查找用于执行比较的键的函数。
public static class EnumerableExtensions { public static IEnumerable<TSource> Exclude<TSource, TKey>(this IEnumerable<TSource> source, IEnumerable<TSource> exclude, Func<TSource, TKey> keySelector) { var excludedSet = new HashSet<TKey>(exclude.Select(keySelector)); return source.Where(item => !excludedSet.Contains(keySelector(item))); } }
你可以这样使用它
list1.Exclude(list2, i => i.ID);
这是一个可以获得应聘者尚不具备的IT技能的工作示例。
//Get a list of skills from the Skill table IEnumerable<Skill> skillenum = skillrepository.Skill; //Get a list of skills the candidate has IEnumerable<CandSkill> candskillenum = candskillrepository.CandSkill .Where(p => p.Candidate_ID == Candidate_ID); //Using the enum lists with LINQ filter out the skills not in the candidate skill list IEnumerable<Skill> skillenumresult = skillenum.Where(p => !candskillenum.Any(p2 => p2.Skill_ID == p.Skill_ID)); //Assign the selectable list to a viewBag ViewBag.SelSkills = new SelectList(skillenumresult, "Skill_ID", "Skill_Name", 1);