Trova un elemento in Elenco di LINQ?


226

Qui ho un semplice esempio per trovare un elemento in un elenco di stringhe. Normalmente utilizzo per loop o delegato anonimo per farlo in questo modo:

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 è nuovo per me. Sono curioso di sapere se posso usare LINQ per trovare l'elemento nell'elenco? Come possibile?


È fantastico. Tuttavia, quelli sono tutti stile di espressione lamda. Uso un semplice elenco qui. L'elenco può essere una classe con diverse proprietà e alcune vengono utilizzate per la ricerca. Quindi qualsiasi modo LINQ per cercare come "from .. in ... where ... select ..."
David.Chu.ca

No, scusa. La maggior parte di questi metodi (First, Single, Any, ...) non possono essere tradotti direttamente in quel modulo.
R. Martinho Fernandes,

Non importa, in realtà puoi sbarazzarti degli lambda per alcuni casi ...
R. Martinho Fernandes,

Grandi risposte! Voglio solo avere un assaggio della ricerca LINQ dal caso di enumerazione.
David.Chu.ca,

Risposte:


478

Ci sono alcuni modi (nota che questo non è un elenco completo).

1) Single restituirà un singolo risultato, ma genererà un'eccezione se ne trova uno o più di uno (che può essere o meno quello che vuoi):

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

Nota SingleOrDefault()si comporterà allo stesso modo, tranne per il fatto che restituirà null per i tipi di riferimento o il valore predefinito per i tipi di valore, invece di generare un'eccezione.

2) Dove restituirà tutti gli articoli che corrispondono ai tuoi criteri, quindi potresti ottenere un IEnumerable con un elemento:

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

3) First restituirà il primo articolo che corrisponde ai tuoi criteri:

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

Nota FirstOrDefault()si comporterà allo stesso modo, tranne per il fatto che restituirà null per i tipi di riferimento o il valore predefinito per i tipi di valore, invece di generare un'eccezione.


35
Bella risposta. Ho trovato SingleOrDefault la mia risposta preferita - lo stesso di Single ma restituisce 'null' se non riesce a trovarlo.
Eddie Parker

2
Non conoscevo Single () o SingleOrDefault (). Molto utile.
draconis,

Questi metodi possono essere usati anche con altre raccolte come ReadOnlyCollectiono ObservableCollection?
yellavon,

@yellavon questi sono metodi di estensione su qualsiasi tipo che implementa IEnumerable<T>oIQueryable<T>
Rex M

4
Una cosa da notare sull'uso di SingleOrDefault è che, poiché genera un'eccezione se nell'elenco è presente più di una corrispondenza, deve scorrere ogni elemento, dove FirstOrDefault interromperà la ricerca una volta trovata la prima corrispondenza. msdn.microsoft.com/en-us/library/bb342451(v=vs.110).aspx
DavidWainwright

73

Se vuoi l'indice dell'elemento, questo lo farà:

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

Non puoi liberarti della lambda nel primo passaggio.

Nota che questo verrà lanciato se l'oggetto non esiste. Questo risolve il problema ricorrendo a null nullable:

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

Se vuoi l'articolo:

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

Se si desidera contare il numero di elementi corrispondenti:

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

Se vuoi tutti gli articoli corrispondenti:

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

E non dimenticare di controllare l'elenco nullin uno di questi casi.

Oppure usa (list ?? Enumerable.Empty<string>())invece di list.

Grazie a Pavel per l'aiuto nei commenti.


2
Due punti. In primo luogo, non c'è davvero bisogno di usare string.Equalsqui - niente di sbagliato in ==. In secondo luogo, vorrei anche menzionare FirstOrDefault(per i casi in cui l'articolo potrebbe non essere lì) e Selectcon indice per coprire il caso in cui è necessario l'indice dell'articolo (come è nell'esempio nella domanda stessa).
Pavel Minaev,

Non sono ancora felice. Non c'è un indice -1 (non trovato) nel mio esempio. Qualche suggerimento?
R. Martinho Fernandes,

Oltre a verificarne l'esistenza con if, per primo.
R. Martinho Fernandes,

Devo verificare se l'elenco è prima null?
David.Chu.ca,

Seleziona genera ArgumentNullExceptionse la fonte è nulla
R. Martinho Fernandes

13

Se è davvero un List<string>non è necessario LINQ, basta usare:

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

Se stai cercando l'articolo stesso, prova:

string GetItem(string search)
{
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}

1
Seguendo la logica del primo esempio, potremmo usare _list.Find(search)per il secondo.
jwg

12

Vuoi l'articolo nella lista o l'oggetto reale stesso (assumerebbe l'articolo stesso).

Ecco un sacco di opzioni per te:

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

Whoa ... alcune persone sono super veloci il grilletto;)
Kelsey

che ne dici di indicizzare come valore di ritorno?
David.Chu.ca,

e devo verificare se _list è null sotto forma di from .. in _list ...?
David.Chu.ca,

6

Questo metodo è più semplice e sicuro

var lOrders = new List<string>();

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


1
Penso che non abbiamo nemmeno bisogno di true : falsesotto dovrebbe funzionare lo stesso bool insertOrderNew = lOrders.Find(r => r == "1234") == null;
Vbp

5

Che ne dici IndexOf?

Cerca l'oggetto specificato e restituisce l'indice della prima occorrenza nell'elenco

Per esempio

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

Si noti che restituisce -1 se il valore non si trova nell'elenco

> boys.IndexOf("Hermione")  
-1

2

Ho usato un dizionario che è una specie di elenco indicizzato che mi darà esattamente quello che voglio quando lo voglio.

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

Ogni volta che desidero accedere ai valori dei miei margini, ad esempio, rivolgo al mio dizionario:

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

Quindi, a seconda di cosa stai facendo, un dizionario può essere utile.


Ottima risposta a una domanda diversa.
jwg

2

Ecco un modo per riscrivere il metodo per utilizzare LINQ:

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

Quindi, chiamandolo con

GetItemIndex("two")tornerà 1,

e

GetItemIndex("notthere")tornerà -1.

Riferimento: linqsamples.com


1

Prova questo codice:

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

1

Se abbiamo bisogno di trovare un elemento dall'elenco, allora possiamo usare il metodo Finde FindAllextensions, ma c'è una leggera differenza tra loro. Ecco un esempio

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

1

Questo ti aiuterà a ottenere il primo o il valore predefinito nella ricerca dell'elenco Linq

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

Questa ricerca troverà il primo o il valore predefinito che restituirà.


0

Si desidera cercare un oggetto nell'elenco degli oggetti.

Questo ti aiuterà a ottenere il primo o il valore predefinito nella ricerca dell'elenco Linq.

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

o

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

0

È possibile utilizzare FirstOfDefault con l'estensione Where Linq per ottenere una classe MessageAction da IEnumerable. Reme

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

dove

Elenco azioni {get; impostato; }

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.