你会如何使用LINQ进行"不在"查询?

Bre*_*nan 291 c# linq

我有两个集合,Email在两个集合中都有属性.我需要获取第一个列表中Email第二个列表中不存在的项目列表.使用SQL我只会使用"not in",但我不知道LINQ中的等价物.怎么做的?

到目前为止,我有一个加入,像......

var matches = from item1 in list1
join item2 in list2 on item1.Email equals item2.Email
select new { Email = list1.Email };
Run Code Online (Sandbox Code Playgroud)

但我不能加入,因为我需要差异,加入会失败.我需要一些使用Contains或Exists的方法我相信.我还没有找到一个例子来做到这一点.

Ech*_*orm 321

你想要Except运算符.

var answer = list1.Except(list2);
Run Code Online (Sandbox Code Playgroud)

这里有更好的解释:http://blogs.msdn.com/charlie/archive/2008/07/12/the-linq-set-operators.aspx

注意:此技术仅适用于基本类型,因为您必须实现IEqualityComparer才能使用具有复杂类型的Except方法.

  • 使用Except:如果您使用复杂类型列表,那么您必须实现IEqualityComparer <MyComlplexType>,它使它不那么好 (7认同)
  • 如果你只想比较引用相等或者你已经覆盖了T.Equals()和T.GetHashCode(),那么你不能**实现IEqualityComparer <T>.如果未实现IEqualityComparer <T>,将使用[EqualityComparer <T> .Default](http://stackoverflow.com/a/17225006/1925996). (4认同)
  • @Echostorm(以及其他人阅读),如果你做一个Select to Anonymous对象,HashCode将由属性值决定; `list1.Select(item => new {Property1 = item.Property1,Property2 = item.Property2}).除外(list2.Select(item => new {Property1 = item.Property1,Property2 = item.Property2})); `当您通过仅评估复杂类型的一组值来确定相等性时,这尤其有用. (2认同)
  • 实际上,下面有人指出,我正确地认为,不需要在LinqToSql场景中实现IEquatityComparor &lt;T,T&gt;或重写对象比较方法。对于,查询将表示为/编译为/表示为SQL;因此将检查值,而不是对象引用。 (2认同)
  • 使用`except`,我能够将LINQ查询从8-10秒加速到半秒 (2认同)

Rob*_*use 289

我不知道这对你有帮助,但是......

NorthwindDataContext dc = new NorthwindDataContext();    
dc.Log = Console.Out;

var query =    
    from c in dc.Customers    
    where !(from o in dc.Orders    
            select o.CustomerID)    
           .Contains(c.CustomerID)    
    select c;

foreach (var c in query) Console.WriteLine( c );
Run Code Online (Sandbox Code Playgroud)

在LINQ的NOT IN子句中SQL马可·鲁索

  • LINQ to Entities对我来说很好用.SQL成为WHERE NOT EXISTS(子查询)查询.也许有更新解决了这个问题? (13认同)
  • @Robert Rouse - linq to sql中的The Not in cluse链接不再有效.只是一个fyi. (4认同)
  • 我认为EF的新版本确实支持.Contains,加上这个问题没有标记EF(版本)或LinqToSQL ..所以可能需要在这里讨论问题和答案. (2认同)

Str*_*ior 60

对于以一组内存中对象开头并且正在查询数据库的人,我发现这是最好的方法:

var itemIds = inMemoryList.Select(x => x.Id).ToArray();
var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id));
Run Code Online (Sandbox Code Playgroud)

WHERE ... IN (...)在SQL中生成一个nice 子句.


Amy*_*y B 58

第一个列表中第二个列表中不存在电子邮件的项目.

from item1 in List1
where !(list2.Any(item2 => item2.Email == item1.Email))
select item1;
Run Code Online (Sandbox Code Playgroud)


Dev*_*evT 15

您可以使用Where和Any的组合来查找不在:

var NotInRecord =list1.Where(p => !list2.Any(p2 => p2.Email  == p.Email));
Run Code Online (Sandbox Code Playgroud)


小智 8

您可以将这两个集合放在两个不同的列表中,例如list1和list2.

然后就写

list1.RemoveAll(Item => list2.Contains(Item));
Run Code Online (Sandbox Code Playgroud)

这会奏效.

  • 很好,但是具有从列表中删除元素的副作用。 (3认同)

Bre*_*ett 7

在使用ADO.NET实体框架的情况下,EchoStorm的解决方案也可以完美运行.但我花了几分钟时间绕过它.假设您有一个数据库上下文dc,并希望在表x中找不到表y中未链接的行,则完整的答案答案如下所示:

var linked =
  from x in dc.X
  from y in dc.Y
  where x.MyProperty == y.MyProperty
  select x;
var notLinked =
  dc.X.Except(linked);
Run Code Online (Sandbox Code Playgroud)

回答Andy的评论,是的,在LINQ查询中可以有两个来自.这是一个完整的工作示例,使用列表.每个类Foo和Bar都有一个Id.Foo有一个"外键"引用Bar via Foo.BarId.程序选择未链接到相应Bar的所有Foo.

class Program
{
    static void Main(string[] args)
    {
        // Creates some foos
        List<Foo> fooList = new List<Foo>();
        fooList.Add(new Foo { Id = 1, BarId = 11 });
        fooList.Add(new Foo { Id = 2, BarId = 12 });
        fooList.Add(new Foo { Id = 3, BarId = 13 });
        fooList.Add(new Foo { Id = 4, BarId = 14 });
        fooList.Add(new Foo { Id = 5, BarId = -1 });
        fooList.Add(new Foo { Id = 6, BarId = -1 });
        fooList.Add(new Foo { Id = 7, BarId = -1 });

        // Create some bars
        List<Bar> barList = new List<Bar>();
        barList.Add(new Bar { Id = 11 });
        barList.Add(new Bar { Id = 12 });
        barList.Add(new Bar { Id = 13 });
        barList.Add(new Bar { Id = 14 });
        barList.Add(new Bar { Id = 15 });
        barList.Add(new Bar { Id = 16 });
        barList.Add(new Bar { Id = 17 });

        var linked = from foo in fooList
                     from bar in barList
                     where foo.BarId == bar.Id
                     select foo;
        var notLinked = fooList.Except(linked);
        foreach (Foo item in notLinked)
        {
            Console.WriteLine(
                String.Format(
                "Foo.Id: {0} | Bar.Id: {1}",
                item.Id, item.BarId));
        }
        Console.WriteLine("Any key to continue...");
        Console.ReadKey();
    }
}

class Foo
{
    public int Id { get; set; }
    public int BarId { get; set; }
}

class Bar
{
    public int Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)


Jan*_* S. 6

一个也可以使用 All()

var notInList = list1.Where(p => list2.All(p2 => p2.Email != p.Email));
Run Code Online (Sandbox Code Playgroud)