Suchen Sie einen Artikel in der Liste von LINQ?

226

Hier habe ich ein einfaches Beispiel, um ein Element in einer Liste von Zeichenfolgen zu finden. Normalerweise verwende ich for loop oder einen anonymen Delegaten, um dies folgendermaßen zu tun:

int GetItemIndex(string search)
{
   int found = -1;
   if ( _list != null )
   {
     foreach (string item in _list) // _list is an instance of List<string>
     { 
        found++;
        if ( string.Equals(search, item) )
        {
           break;
        }
      }
      /* use anonymous delegate
      string foundItem = _list.Find( delegate(string item) {
         found++;
         return string.Equals(search, item);
      });
      */
   }
   return found;
}

LINQ ist neu für mich. Ich bin gespannt, ob ich mit LINQ einen Artikel in der Liste finden kann. Wie wenn möglich?

David.Chu.ca
quelle
Das ist großartig. Dies sind jedoch alle Lamda-Ausdrucksstile. Ich benutze hier eine einfache Liste. Die Liste kann eine Klasse mit mehreren Eigenschaften sein und einige werden für die Suche verwendet. Also jede LINQ-Art zu suchen wie "von ... in ... wo ... auswählen ..."
David.Chu.ca
Nein, tut mir leid. Die meisten dieser Methoden (First, Single, Any, ...) können nicht direkt in diese Form übersetzt werden.
R. Martinho Fernandes
Egal, eigentlich können Sie die Lambdas für ein paar Fälle loswerden ...
R. Martinho Fernandes
Tolle Antworten! Ich möchte nur einen Vorgeschmack auf die LINQ-Suche aus dem Aufzählungsfall erhalten.
David.Chu.ca

Antworten:

477

Es gibt einige Möglichkeiten (beachten Sie, dass dies keine vollständige Liste ist).

1) Single gibt ein einzelnes Ergebnis zurück, löst jedoch eine Ausnahme aus, wenn keine oder mehrere gefunden werden (die möglicherweise das sind, was Sie möchten oder nicht):

string search = "lookforme";
List<string> myList = new List<string>();
string result = myList.Single(s => s == search);

Hinweis SingleOrDefault()verhält sich gleich, außer dass für Referenztypen null oder für Werttypen der Standardwert zurückgegeben wird, anstatt eine Ausnahme auszulösen.

2) Wo werden alle Elemente zurückgegeben, die Ihren Kriterien entsprechen, sodass Sie möglicherweise eine IEnumerable mit einem Element erhalten:

IEnumerable<string> results = myList.Where(s => s == search);

3) Zuerst wird der erste Artikel zurückgegeben, der Ihren Kriterien entspricht:

string result = myList.First(s => s == search);

Hinweis FirstOrDefault()verhält sich gleich, außer dass für Referenztypen null oder für Werttypen der Standardwert zurückgegeben wird, anstatt eine Ausnahme auszulösen.

Rex M.
quelle
35
Gute Antwort. Ich fand, dass SingleOrDefault meine Antwort der Wahl ist - genau wie Single, aber 'null' zurückgibt, wenn es nicht gefunden werden kann.
Eddie Parker
2
Ich kannte weder Single () noch SingleOrDefault (). Sehr hilfreich.
Draconis
Können diese Methoden auch mit anderen Sammlungen wie ReadOnlyCollectionoder verwendet werden ObservableCollection?
Yellavon
@yellavon Dies sind Erweiterungsmethoden für jeden Typ, der implementiert IEnumerable<T>oderIQueryable<T>
Rex M
4
Bei der Verwendung von SingleOrDefault ist zu beachten, dass, da eine Ausnahme ausgelöst wird, wenn mehr als eine Übereinstimmung in der Liste enthalten ist, alle Elemente durchlaufen werden müssen, bei denen FirstOrDefault die Suche beendet, sobald die erste Übereinstimmung gefunden wurde. msdn.microsoft.com/en-us/library/bb342451(v=vs.110).aspx
DavidWainwright
73

Wenn Sie den Index des Elements möchten, tun Sie dies:

int index = list.Select((item, i) => new { Item = item, Index = i })
                .First(x => x.Item == search).Index;

// or
var tagged = list.Select((item, i) => new { Item = item, Index = i });
int index = (from pair in tagged
            where pair.Item == search
            select pair.Index).First();

Sie können das Lambda nicht im ersten Durchgang loswerden.

Beachten Sie, dass dies ausgelöst wird, wenn der Gegenstand nicht existiert. Dies löst das Problem, indem auf nullbare Ints zurückgegriffen wird:

var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i });
int? index = (from pair in tagged
            where pair.Item == search
            select pair.Index).FirstOrDefault();

Wenn Sie den Artikel möchten:

// Throws if not found
var item = list.First(item => item == search);
// or
var item = (from item in list
            where item == search
            select item).First();

// Null if not found
var item = list.FirstOrDefault(item => item == search);
// or
var item = (from item in list
            where item == search
            select item).FirstOrDefault();

Wenn Sie die Anzahl der übereinstimmenden Elemente zählen möchten:

int count = list.Count(item => item == search);
// or
int count = (from item in list
            where item == search
            select item).Count();

Wenn Sie alle Elemente möchten, die übereinstimmen:

var items = list.Where(item => item == search);
// or
var items = from item in list
            where item == search
            select item;

Und vergessen Sie nullin keinem dieser Fälle , die Liste zu überprüfen .

Oder verwenden Sie (list ?? Enumerable.Empty<string>())anstelle vonlist .

Vielen Dank an Pavel für die Hilfe in den Kommentaren.

R. Martinho Fernandes
quelle
2
Zwei Punkte. Erstens gibt es hier keine wirkliche Notwendigkeit string.Equals- nichts Falsches daran ==. Zweitens würde ich auch erwähnen FirstOrDefault(für Fälle, in denen ein Artikel möglicherweise nicht vorhanden ist) und Selectmit einem Index, um den Fall abzudecken, in dem ein Index des Artikels benötigt wird (wie im Beispiel in der Frage selbst).
Pavel Minaev
Ich bin noch nicht glücklich In meinem Beispiel gibt es keinen -1-Index (nicht gefunden). Irgendein Vorschlag?
R. Martinho Fernandes
Neben der Überprüfung der Existenz mit if, first.
R. Martinho Fernandes
Muss ich zuerst überprüfen, ob die Liste null ist?
David.Chu.ca
Wählen Sie Würfe, ArgumentNullExceptionwenn die Quelle null ist
R. Martinho Fernandes
13

Wenn es wirklich ein List<string>LINQ ist, verwenden Sie einfach:

int GetItemIndex(string search)
{
    return _list == null ? -1 : _list.IndexOf(search);
}

Wenn Sie nach dem Artikel selbst suchen, versuchen Sie:

string GetItem(string search)
{
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}
AgileJon
quelle
1
Nach der Logik des ersten Beispiels könnten wir _list.Find(search)für das zweite verwenden.
JWG
12

Möchten Sie das Element in der Liste oder das tatsächliche Element selbst (würde das Element selbst annehmen).

Hier sind eine Reihe von Optionen für Sie:

string result = _list.First(s => s == search);

string result = (from s in _list
                 where s == search
                 select s).Single();

string result = _list.Find(search);

int result = _list.IndexOf(search);
Kelsey
quelle
Whoa ... einige Leute sind super schnell einer der Auslöser;)
Kelsey
Wie wäre es mit Index als Rückgabewert?
David.Chu.ca
und muss ich überprüfen, ob _list null in Form von from .. in _list ... ist?
David.Chu.ca
6

Diese Methode ist einfacher und sicherer

var lOrders = new List<string>();

bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false

RckLN
quelle
1
Ich denke, wir brauchen nicht einmal true : falseunten sollte gleich funktionieren bool insertOrderNew = lOrders.Find(r => r == "1234") == null;
Vbp
5

Wie wäre es IndexOf?

Sucht nach dem angegebenen Objekt und gibt den Index des ersten Vorkommens in der Liste zurück

Beispielsweise

> var boys = new List<string>{"Harry", "Ron", "Neville"};  
> boys.IndexOf("Neville")  
2
> boys[2] == "Neville"
True

Beachten Sie, dass -1 zurückgegeben wird, wenn der Wert nicht in der Liste vorkommt

> boys.IndexOf("Hermione")  
-1
Oberst Panik
quelle
2

Früher habe ich ein Wörterbuch verwendet, eine Art indizierte Liste, die mir genau das gibt, was ich will, wenn ich es will.

Dictionary<string, int> margins = new Dictionary<string, int>();
margins.Add("left", 10);
margins.Add("right", 10);
margins.Add("top", 20);
margins.Add("bottom", 30);

Wenn ich beispielsweise auf meine Randwerte zugreifen möchte, adressiere ich mein Wörterbuch:

int xStartPos = margins["left"];
int xLimitPos = margins["right"];
int yStartPos = margins["top"];
int yLimitPos = margins["bottom"];

Je nachdem, was Sie tun, kann ein Wörterbuch hilfreich sein.

Will Marcouiller
quelle
Tolle Antwort auf eine andere Frage.
JWG
2

Hier ist eine Möglichkeit, Ihre Methode für die Verwendung von LINQ neu zu schreiben:

public static int GetItemIndex(string search)
{
    List<string> _list = new List<string>() { "one", "two", "three" };

    var result = _list.Select((Value, Index) => new { Value, Index })
            .SingleOrDefault(l => l.Value == search);

    return result == null ? -1 : result.Index;
}

Also nenne es mit

GetItemIndex("two")wird zurückkehren 1,

und

GetItemIndex("notthere")wird zurückkehren -1.

Referenz: linqsamples.com

Brinch
quelle
1

Versuchen Sie diesen Code:

return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID });
Nayeem Mansoori
quelle
1

Wenn wir ein Element aus der Liste suchen müssen, können wir die Methode Findund FindAllextensions verwenden, aber es gibt einen kleinen Unterschied zwischen ihnen. Hier ist ein Beispiel.

 List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 };

  // It will return only one 8 as Find returns only the first occurrence of matched elements.
     var result = items.Find(ls => ls == 8);      
 // this will returns three {8,8,8} as FindAll returns all the matched elements.
      var result1 = items.FindAll(ls => ls == 8); 
Sheo Dayal Singh
quelle
1

Dies hilft Ihnen dabei, den ersten oder Standardwert in Ihrer Linq List-Suche zu erhalten

var results = _List.Where(item => item == search).FirstOrDefault();

Diese Suche findet den ersten oder Standardwert, den sie zurückgibt.

befree2j
quelle
0

Sie möchten ein Objekt in der Objektliste suchen.

Dies hilft Ihnen dabei, den ersten oder Standardwert in Ihrer Linq List-Suche zu erhalten.

var item = list.FirstOrDefault(items =>  items.Reference == ent.BackToBackExternalReferenceId);

oder

var item = (from items in list
    where items.Reference == ent.BackToBackExternalReferenceId
    select items).FirstOrDefault();
Huseyin Durmus
quelle
0

Sie können FirstOfDefault mit der Where Linq-Erweiterung verwenden, um eine MessageAction-Klasse aus dem IEnumerable abzurufen. Reme

var action = Message.Actions.Where (e => e.targetByName == className) .FirstOrDefault ();

wo

Aktionen auflisten {get; einstellen; }}

Goldener Löwe
quelle