使用LINQ获取一个List<>中的项目,这些项目不在另一个List<>中

时间:2010-10-15 18:00:28

标签: c# linq .net-3.5

我会假设有一个简单的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 });
    }
}

class Person
{
    public int ID { get; set; }
}

我想执行一个LINQ查询,以便让peopleList2peopleList1以内的所有人都不在{{1}}这个例子应该给我两个人(ID = 4&amp; ID = 5)

10 个答案:

答案 0 :(得分:772)

var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));

答案 1 :(得分:329)

如果您覆盖人员的相等性,那么您也可以使用:

peopleList2.Except(peopleList1)

Except应该明显快于Where(...Any)变体,因为它可以将第二个列表放入哈希表中。 Where(...Any)的运行时间为O(peopleList1.Count * peopleList2.Count),而基于HashSet<T>的变体(几乎)的运行时间为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));

此变体不会删除重复项。

答案 2 :(得分:58)

或者如果你想要它而没有否定:

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));

基本上它说来自peopleList2的所有内容,其中peopleList1中的所有ID都与peoplesList2中的id不同。

与接受的答案略有不同的方法:)

答案 3 :(得分:28)

由于迄今为止所有的解决方案都使用了流利的语法,这里有一个查询表达式语法的解决方案,对于那些感兴趣的人:

var peopleDifference = 
  from person2 in peopleList2
  where !(
      from person1 in peopleList1 
      select person1.ID
    ).Contains(person2.ID)
  select person2;

我认为它与某些人感兴趣的答案有所不同,甚至认为它很可能对于列表而言不是最理想的。现在对于具有索引ID的表,这肯定是要走的路。

答案 4 :(得分:13)

派对迟到了,但Linq与SQL兼容的一个很好的解决方案是:

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

答案 5 :(得分:8)

克劳斯&#39;答案很棒,但ReSharper会要求你简化LINQ表达式&#34;:

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));

答案 6 :(得分:7)

此Enumerable Extension允许您定义要排除的项目列表以及用于查找用于执行比较的键的函数。

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);

答案 7 :(得分:0)

这是一个工作示例,可以获得求职者没有的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);

答案 8 :(得分:0)

首先,从条件所在的集合中提取ID

List<int> indexes_Yes = this.Contenido.Where(x => x.key == 'TEST').Select(x => x.Id).ToList();

第二次,使用“比较”方式选择与选择内容不同的ID

List<int> indexes_No = this.Contenido.Where(x => !indexes_Yes.Contains(x.Id)).Select(x => x.Id).ToList();

很明显,您可以使用x.key!=“ TEST”,但这只是一个示例

答案 9 :(得分:0)

一旦编写了通用的FuncEqualityComparer,就可以在任何地方使用它。

peopleList2.Except(peopleList1, new FuncEqualityComparer<Person>((p, q) => p.ID == q.ID));

public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> comparer;
    private readonly Func<T, int> hash;

    public FuncEqualityComparer(Func<T, T, bool> comparer)
    {
        this.comparer = comparer;
        if (typeof(T).GetMethod(nameof(object.GetHashCode)).DeclaringType == typeof(object))
            hash = (_) => 0;
        else
            hash = t => t.GetHashCode(); 
    }

    public bool Equals(T x, T y) => comparer(x, y);
    public int GetHashCode(T obj) => hash(obj);
}