349 Stimmen

Wie würden Sie eine "nicht in" Abfrage mit LINQ tun?

Ich habe zwei Sammlungen, die die Eigenschaft Email in beiden Sammlungen. Ich muss eine Liste der Elemente in der ersten Liste erhalten, in der Email ist in der zweiten Liste nicht vorhanden. Bei SQL würde ich einfach "not in" verwenden, aber ich kenne die Entsprechung in LINQ nicht. Wie wird das gemacht?

Bis jetzt 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 verbinden, da ich die Differenz brauche und die Verbindung fehlschlagen würde. Ich brauche eine Möglichkeit, Contains oder Exists ich glaube zu verwenden. Ich habe nur noch kein Beispiel gefunden, um das zu tun.

8voto

Janis S. Punkte 2418

Man könnte auch verwenden All()

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

7voto

Brett Punkte 8456

In dem Fall, dass man die ADO.NET Entity Framework Die Lösung von EchoStorm funktioniert ebenfalls perfekt. Aber ich habe ein paar Minuten gebraucht, um sie zu begreifen. Angenommen, Sie haben einen Datenbankkontext, dc, und wollen Zeilen in Tabelle x finden, die nicht mit Tabelle y verknüpft sind, 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, ja, man kann zwei from's in einer LINQ-Abfrage haben. Hier ist ein vollständiges Arbeitsbeispiel, das Listen verwendet. Jede Klasse, Foo und Bar, hat eine Id. Foo hat einen "Fremdschlüssel"-Verweis auf Bar über Foo.BarId. Das Programm wählt alle Foo's aus, die nicht mit einer entsprechenden Bar 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; }
}

5voto

Chintan Udeshi Punkte 79

Sie können die beiden Sammlungen in zwei verschiedene Listen aufnehmen, z. B. list1 und list2.

Dann schreiben Sie einfach

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

Das wird funktionieren.

4voto

tvanfosson Punkte 506878
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};

3voto

Ryan Lundy Punkte 195074

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

  • implementieren IEquatable<T> in Ihrer Schrift, oder
  • Überschreiben Sie Equals et GetHashCode in Ihrer Schrift, oder
  • eine Instanz eines Typs übergeben, der IEqualityComparer<T> für Ihren Typ

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X