251 votes

Trouver un élément dans une liste par LINQ ?

Voici un exemple simple pour trouver un élément dans une liste de chaînes de caractères. Normalement, j'utilise une boucle for ou un délégué anonyme pour le faire comme ceci :

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 est nouveau pour moi. Je suis curieux de savoir si je peux utiliser LINQ pour trouver un élément dans une liste ? Comment, si possible ?

0 votes

C'est très bien. Cependant, ce sont tous des styles d'expression lamda. J'utilise ici une simple liste. La liste peut être une classe avec plusieurs propriétés et certaines sont utilisées pour la recherche. Donc n'importe quelle façon LINQ de rechercher comme "from .. in ... where... select..."

0 votes

Non, désolé. La plupart de ces méthodes (First, Single, Any, ...) ne peuvent pas être directement traduit sous cette forme.

0 votes

Peu importe, en fait on peut se débarrasser des lambdas dans certains cas...

541voto

Rex M Points 80372

Il y a quelques moyens (notez que c'est pas une liste complète).

1) Simple renverra un seul résultat, mais lèvera une exception si elle n'en trouve aucun ou plus d'un (ce qui peut ou non être ce que vous voulez) :

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

Note SingleOrDefault() se comportera de la même manière, sauf qu'il retournera null pour les types de référence, ou la valeur par défaut pour les types de valeur, au lieu de lever une exception.

2) renverra tous les éléments qui correspondent à vos critères, de sorte que vous pouvez obtenir un IEnumerable avec un seul élément :

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

3) Premier retournera le premier élément qui correspond à vos critères :

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

Note FirstOrDefault() se comportera de la même manière, sauf qu'il retournera null pour les types de référence, ou la valeur par défaut pour les types de valeur, au lieu de lever une exception.

42 votes

Excellente réponse. J'ai trouvé que SingleOrDefault était ma réponse de choix - c'est la même chose que Single mais il renvoie 'null' s'il ne peut pas le trouver.

3 votes

Je ne connaissais ni Single() ni SingleOrDefault(). Très utile.

0 votes

Ces méthodes peuvent-elles être utilisées avec d'autres collections, par exemple ReadOnlyCollection ou ObservableCollection ?

77voto

Si vous voulez l'index de l'élément, cela le fera :

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

Vous ne pouvez pas vous débarrasser de la lambda dans la première passe.

Notez que cette opération sera rejetée si l'élément n'existe pas. Cela résout le problème en recourant à des ints nullables :

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

Si vous voulez l'article :

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

Si vous voulez compter le nombre d'éléments qui correspondent :

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

Si vous voulez tous les articles qui correspondent :

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

Et n'oubliez pas de vérifier la liste pour null dans l'un ou l'autre de ces cas.

Ou utilisez (list ?? Enumerable.Empty<string>()) au lieu de list .

Merci à Pavel pour son aide dans les commentaires.

2 votes

Deux points. Premièrement, il n'y a pas vraiment besoin d'utiliser string.Equals ici - rien de mal à == . Deuxièmement, je mentionnerais également FirstOrDefault (pour les cas où l'élément pourrait ne pas être là), et Select avec index pour couvrir le cas où l'index de l'élément est nécessaire (comme c'est le cas dans l'échantillon de la question elle-même).

0 votes

Je ne suis pas encore satisfait. Il n'y a pas d'index -1 (not found) dans mon exemple. Une suggestion ?

0 votes

En plus de vérifier son existence avec if, d'abord.

12voto

AgileJon Points 20497

Si c'est vraiment un List<string> vous n'avez pas besoin de LINQ, il suffit d'utiliser :

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

Si vous cherchez l'article lui-même, essayez :

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

1 votes

En suivant la logique du premier exemple, nous pourrions utiliser _list.Find(search) pour le second.

12voto

Kelsey Points 26456

Voulez-vous l'article dans la liste ou l'article lui-même (je suppose que l'article lui-même).

Voici une série d'options pour vous :

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

0 votes

Whoa... certaines personnes sont super rapides sur la gâchette ;)

0 votes

pourquoi pas l'index comme valeur de retour ?

0 votes

et dois-je vérifier si _list est nulle sous la forme de from .. in _list... ?

6voto

RckLN Points 920

Cette méthode est plus facile et plus sûre

var lOrders = new List<string>();

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

2 votes

Je pense que nous n'avons même pas besoin true : false ci-dessous devrait fonctionner de la même manière bool insertOrderNew = lOrders.Find(r => r == "1234") == null;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X