it-swarm.com.de

Wie würden Sie mit LINQ eine Nicht-In-Abfrage durchführen?

Ich habe zwei Sammlungen, die Eigenschaft Email in beiden Sammlungen haben. Ich muss eine Liste der Elemente in der ersten Liste abrufen, in der Email nicht in der zweiten Liste vorhanden ist. Mit SQL würde ich nur "nicht in" verwenden, aber ich kenne das Äquivalent in LINQ nicht. Wie geht das?

Bisher habe ich eine Verbindung, wie ...

var matches = from item1 in list1
join item2 in list2 on item1.Email equals item2.Email
select new { Email = list1.Email };

Aber ich kann nicht beitreten, da ich den Unterschied brauche und der Beitritt fehlschlagen würde. Ich brauche eine Möglichkeit, Contains oder Exists zu verwenden, wie ich glaube. Ich habe nur noch kein Beispiel dafür gefunden.

286
Brennan

Ich weiß nicht, ob dir das helfen wird, aber ..

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

from Die NOT IN-Klausel in LINQ to SQL by Marco Russo

282
Robert Rouse

Sie möchten den Operator Except.

var answer = list1.Except(list2);

Bessere Erklärung hier: http://blogs.msdn.com/charlie/archive/2008/07/12/the-linq-set-operators.aspx

HINWEIS: Diese Technik eignet sich am besten nur für primitive Typen, da Sie IEqualityComparer implementieren müssen, um die Except-Methode mit complex zu verwenden Typen.

318
Echostorm

Für Benutzer, die mit einer Gruppe von In-Memory-Objekten beginnen und eine Datenbank abfragen, ist dies der beste Weg:

var itemIds = inMemoryList.Select(x => x.Id).ToArray();
var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id));

Dies erzeugt eine Nice WHERE ... IN (...) -Klausel in SQL.

58

elemente in der ersten Liste, in denen die E-Mail nicht in der zweiten Liste vorhanden ist.

from item1 in List1
where !(list2.Any(item2 => item2.Email == item1.Email))
select item1;
57
Amy B

Sie können eine Kombination aus Where und Any verwenden, um nicht in:

var NotInRecord =list1.Where(p => !list2.Any(p2 => p2.Email  == p.Email));
14
DevT

Sie können beide Sammlungen in zwei verschiedenen Listen aufnehmen, z. B. Liste1 und Liste2.

Dann schreib einfach

list1.RemoveAll(Item => list2.Contains(Item));

Das wird funktionieren.

8
Chintan Udeshi

Wenn das ADO.NET Entity Framework verwendet wird, funktioniert die EchoStorm-Lösung ebenfalls einwandfrei. Aber ich brauchte ein paar Minuten, um meinen Kopf darum zu wickeln. Angenommen, Sie haben einen Datenbankkontext, dc, und möchten Zeilen in Tabelle x finden, die in Tabelle y nicht verknüpft sind, dann sieht die vollständige Antwort wie folgt aus:

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

Als Antwort auf Andys Kommentar kann man in einer LINQ-Abfrage zwei von haben. Hier ist ein vollständiges Arbeitsbeispiel mit Listen. Jede Klasse, Foo und Bar, hat eine ID. Foo hat einen "Fremdschlüssel" -Referenz auf Bar über Foo.BarId. Das Programm wählt alle Foo's aus, die nicht mit einem entsprechenden Balken verknüpft sind.

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; }
}
7
Brett
var secondEmails = (from item in list2
                    select new { Email = item.Email }
                   ).ToList();

var matches = from item in list1
              where !secondEmails.Contains(item.Email)
              select new {Email = item.Email};
3
tvanfosson

Man könnte auch All() verwenden

var notInList = list1.Where(p => list2.All(p2 => p2.Email != p.Email));
2
Janis S.

Während Except Teil der Antwort ist, ist es nicht die ganze Antwort. Standardmäßig führt Except (wie mehrere der LINQ-Operatoren) einen Referenzvergleich für Referenztypen durch. Um nach Werten in den Objekten zu vergleichen, müssen Sie

  • implementieren Sie IEquatable<T> in Ihren Typ oder
  • überschreiben Sie Equals und GetHashCode in Ihrem Typ, oder
  • übergeben Sie eine Instanz eines Typs, der IEqualityComparer<T> für Ihren Typ implementiert
2
Ryan Lundy

Beispiel zur Vereinfachung mit Liste von int.

List<int> list1 = new List<int>();
// fill data
List<int> list2 = new List<int>();
// fill data

var results = from i in list1
              where !list2.Contains(i)
              select i;

foreach (var result in results)
    Console.WriteLine(result.ToString());
1
Inisheer

Laden Sie dieses Paket herunter, wenn Sie auch einen SQL-ähnlichen IN -Operator in C # verwenden möchten:

Mshwf.NiceLinq

Es hat In und NotIn Methoden:

var result = list1.In(x => x.Email, list2.Select(z => z.Email));

Sogar Sie können es auf diese Weise verwenden

var result = list1.In(x => x.Email, "[email protected]", "[email protected]", "[email protected]");
1
mshwf

Ich habe dies nicht mit LINQ to Entities getestet:

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

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

Alternative:

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

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

foreach (var c in query) 
    Console.WriteLine( c );
0
Tarik

Vielen Dank, Brett. Ihr Vorschlag hat mir auch geholfen. Ich hatte eine Liste von Objekten und wollte diese anhand einer anderen Liste von Objekten filtern. Danke noch einmal....

Wenn jemand etwas braucht, schauen Sie sich bitte mein Codebeispiel an:

'First, get all the items present in the local branch database
Dim _AllItems As List(Of LocalItem) = getAllItemsAtBranch(BranchId, RecordState.All)

'Then get the Item Mappings Present for the branch
Dim _adpt As New gItem_BranchesTableAdapter
Dim dt As New ds_CA_HO.gItem_BranchesDataTable
    _adpt.FillBranchMappings(dt, BranchId)

Dim _MappedItems As List(Of LocalItem) = (From _item As LocalItem In _AllItems Join _
    dr As ds_CA_HO.gItem_BranchesRow In dt _
    On _item.Id Equals dr.numItemID _
    Select _item).ToList

_AllItems = _AllItems.Except(_MappedItems.AsEnumerable).ToList

 Return _AllItems
0
mangeshkt

Konnten Sie keine äußere Verknüpfung erstellen und nur die Elemente aus der ersten Liste auswählen, wenn die Gruppe leer ist? So etwas wie:

Dim result = (From a In list1
              Group Join b In list2 
                  On a.Value Equals b.Value 
                  Into grp = Group
              Where Not grp.Any
              Select a)

Ich bin mir nicht sicher, ob dies mit dem Entity-Framework auf irgendeine effiziente Weise funktionieren würde.

0
Marten Jacobs