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.