Vérifiez si la liste contient un élément contenant une chaîne et récupérez cet élément


146

En cherchant une réponse à cette question, j'en ai rencontré des similaires en utilisant LINQ mais je n'ai pas été en mesure de les comprendre pleinement (et donc de les mettre en œuvre), car je ne suis pas familiarisé avec cela. Ce que je voudrais, en gros, c'est ceci:

  1. Vérifiez si un élément d'une liste contient une chaîne spécifique.
  2. Si c'est le cas, récupérez cet élément.

Honnêtement, je ne sais pas comment j'y arriverais. Ce que je peux trouver, c'est ceci (ne fonctionne pas, bien sûr):

if (myList.Contains(myString))
    string element = myList.ElementAt(myList.IndexOf(myString));

Je sais pourquoi cela ne fonctionne pas:

  • myList.Contains()ne retourne pas true, car il vérifiera si un élément entier de la liste correspond à la chaîne que j'ai spécifiée.
  • myList.IndexOf() ne trouvera pas d'occurrence, car, comme c'est encore le cas, il recherchera un élément correspondant à la chaîne.

Pourtant, je n'ai aucune idée de la façon de résoudre ce problème, mais je pense que je vais devoir utiliser LINQ comme suggéré dans des questions similaires aux miennes. Cela étant dit, si c'est le cas ici, j'aimerais que le répondant m'explique l'utilisation de LINQ dans son exemple (comme je l'ai dit, je ne me suis pas préoccupé de cela depuis mon temps avec C #). Merci d'avance les gars (et les filles?).

EDIT: J'ai trouvé une solution; bouclez simplement dans la liste, vérifiez si l'élément actuel contient la chaîne, puis définissez une chaîne égale à l'élément actuel. Je me demande, cependant, existe-t-il un moyen plus efficace que cela?

string myString = "bla";
string element = "";

for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Contains(myString))
        element = myList[i];
}

comme je le mentionne dans ma réponse, les boucles à l'ancienne (comme vous l'avez fait pour votre question) sont presque toujours les plus rapides. Mais vous pouvez le tester si vous vous en souciez suffisamment.
McKay

Il peut y avoir plusieurs chaînes dans votre liste contenant votre chaîne myString, dans votre boucle actuelle, vous obtiendrez le dernier élément. Cela dépend de vous si vous voulez trouver le premier ou le dernier, si vous voulez juste trouver le premier, puis rompre la boucle après avoir trouvé l'élément.
Habib le

Réponses:


193

Vous devriez pouvoir utiliser Linq ici:

var matchingvalues = myList
    .Where(stringToCheck => stringToCheck.Contains(myString));

Si vous souhaitez simplement retourner le premier article correspondant:

var match = myList
    .FirstOrDefault(stringToCheck => stringToCheck.Contains(myString));

if(match != null)
    //Do stuff

+1 - Ou remplacez Wherepar FirstOrDefaultdans votre deuxième casmyList.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString))
Habib

Très bonne réponse. Mais par curiosité: pourquoi est matching-ce déterminé par le compilateur ( var)? Puisque je sais que ma liste est de type String, serait-il sûr de l'utiliser string matchingdans ce cas?
Dimitris Iliadis

1
@JimIliadis "var" et "string" signifient exactement la même chose dans ce cas - le compilateur est assez intelligent pour savoir que le résultat ne peut être que "string". var est vraiment juste une chose de style de codage (lorsque vous n'utilisez pas de types anonymes)
Dave Bish

commenter un fil trop ancien, mais a trouvé une exception à ce sujet. lorsque vous utilisez firstordefault (), assurez-vous qu'il peut également renvoyer la valeur par défaut. donc, supposons que vous passiez une chaîne empy ie mystring = "" et que vous n'attendez rien à afficher, mais il affichera quand même le premier élément de la liste car vous avez sélectionné firstordefault.
Dirty Developer

@DirtyDeveloper Je ne sais pas ce que vous entendez par là - votre exemple renverrait 'null, s'il n'y avait pas de chaînes vides dans la liste cible. Vous avez raison si vous essayez d'utiliser FirstOrDefault () sur un type struct, par exemple List <int> - FirstOrDefault () renverra '0' et non null - cependant, la question concernait spécifiquement les chaînes
Dave Bish

29

La réponse de base est la suivante: vous devez parcourir la boucle et vérifier que tout élément contient la chaîne spécifiée. Alors, disons que le code est:

foreach(string item in myList)
{
    if(item.Contains(myString))
       return item;
}

Le code équivalent, mais concis, est:

mylist.Where(x => x.Contains(myString)).FirstOrDefault();

Ici, x est un paramètre qui agit comme "item" dans le code ci-dessus.


12
string result = myList.FirstOrDefault(x => x == myString)
if(result != null)
{
  //found
}

9
for (int i = 0; i < myList.Length; i++)
{
    if (myList[i].Contains(myString)) // (you use the word "contains". either equals or indexof might be appropriate)
    {
        return i;
    }
}

Les boucles à l'ancienne sont presque toujours les plus rapides.


Puisque je privilégie l'efficacité, suggérez-vous que cette méthode est plus rapide (donc plus efficace)?
Dimitris Iliadis

2
Je ne l'ai pas testé, mais je suppose que ce serait plus rapide. Ne nécessite qu'un seul passage dans la liste, jusqu'à ce qu'il trouve quelque chose et éclate tôt (comme les options Linq pourraient le faire si elles étaient bien écrites), n'a pas non plus la surcharge d'invocation de méthode de linq, ni la surcharge lambda de linq. Ce n'est pas que ce soient d'énormes sources de préoccupation, mais cela peut nuire aux performances.
McKay

Pourquoi ne pas utiliser List.Equals ()?
F8ER

@ V.7 Parce qu'il veut seulement savoir si un élément de la liste contient une sous-chaîne. list.equals n'est pas l'outil correct pour le travail ["abc", "def", "ghi"] contient "hi" comme le décrit l'OP. list.equals ne prend même pas les types de données corrects.
McKay

6

Si vous voulez une liste de chaînes contenant votre chaîne:

var newList = myList.Where(x => x.Contains(myString)).ToList();

Une autre option consiste à utiliser Linq FirstOrDefault

var element = myList.Where(x => x.Contains(myString)).FirstOrDefault();

Gardez à l'esprit que cette Containsméthode est sensible à la casse.


1
Bon rappel sur la sensibilité à la casse, implémentez StringComparison.InvariantCultureIgnoreCase
JoshYates1980

2

Vous pouvez utiliser la FirstOrDefaultméthode d'extension de Linq :

string element = myList.FirstOrDefault(s => s.Contains(myString));

Cela retournera le premier élément qui contient la sous-chaîne myString, ou nullsi aucun élément de ce type n'est trouvé.

Si tout ce dont vous avez besoin est l'index, utilisez la méthode de la List<T>classe FindIndex:

int index = myList.FindIndex(s => s.Contains(myString));

Cela retournera l'index du premier élément qui contient la sous-chaîne myString, ou -1si aucun élément de ce type n'est trouvé.


2

Beaucoup de bonnes réponses ici, mais j'en utilise une simple en utilisant Exists , comme ci-dessous:

foreach (var setting in FullList)
{
    if(cleanList.Exists(x => x.ProcedureName == setting.ProcedureName)) 
       setting.IsActive = true; // do you business logic here 
    else
       setting.IsActive = false;
    updateList.Add(setting);
}

2

Vous devriez pouvoir utiliser quelque chose comme ça, cela a bien fonctionné pour moi:

var valuesToMatch = yourList.Where(stringCheck => stringCheck.Contains(myString));

ou quelque chose comme ça, si vous avez besoin de regarder là où cela ne correspond pas.

 var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));

1

vous pouvez utiliser

var match=myList.Where(item=>item.Contains("Required String"));
foreach(var i in match)
{
//do something with the matched items
}

LINQ vous offre des capacités pour «interroger» n'importe quelle collection de données. Vous pouvez utiliser une syntaxe comme une requête de base de données (select, where, etc) sur une collection (ici la collection (liste) de chaînes).

donc vous faites comme "obtenir-moi des éléments de la liste où il satisfait une condition donnée"

à l'intérieur du Où vous utilisez une "expression lambda"

pour dire brièvement l'expression lambda est quelque chose comme (paramètre d'entrée => valeur de retour)

donc pour un paramètre "item", il renvoie "item.Contains (" required string ")". Donc, il retourne true si l'élément contient la chaîne et par conséquent, il est sélectionné dans la liste car il satisfait la condition.


1

Pour rester simple, utilisez ceci;

foreach(string item in myList)//Iterate through each item.
{
 if(item.Contains("Search Term")//True if the item contains search pattern.
 {
   return item;//Return the matched item.
 }
}

Sinon, pour faire cela avec la boucle for, utilisez this;

    for (int iterator = 0; iterator < myList.Count; iterator++)
    {
        if (myList[iterator].Contains("String Pattern"))
        {
            return myList[iterator];
        }
    }

Juste pour faire remarquer, vous avez manqué une parenthèse de fin sur l'une des lignes de code .. if (item.Contains ("Search Term"))
Alex

0

Je n'ai pas vu d'option booléenne dans d'autres réponses, donc j'espère que le code ci-dessous aidera quelqu'un.

Juste utiliser Any()

string myString = "test";
bool exists = myList
             .Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();

0

Il est possible de combiner Any, Where, First et FirstOrDefault; ou placez simplement le prédicat dans l'une de ces méthodes en fonction de ce qui est nécessaire.

Vous devriez probablement éviter d'utiliser First à moins que vous ne souhaitiez qu'une exception soit levée lorsqu'aucune correspondance n'est trouvée. FirstOrDefault est généralement la meilleure option tant que vous savez qu'il renverra la valeur par défaut du type si aucune correspondance n'est trouvée (la valeur par défaut de la chaîne est null, int est 0, bool est faux, etc.).

using System.Collections.Generic;
using System.Linq;


bool exists;
string firstMatch;
IEnumerable<string> matchingList;

var myList = new List<string>() { "foo", "bar", "foobar" };

exists = myList.Any(x => x.Contains("o"));
// exists => true

firstMatch = myList.FirstOrDefault(x => x.Contains("o"));
firstMatch = myList.First(x => x.Contains("o"));
// firstMatch => "foo"

firstMatch = myList.First(x => x.Contains("dark side"));
// throws exception because no element contains "dark side"

firstMatch = myList.FirstOrDefault(x => x.Contains("dark side"));
// firstMatch => null

matchingList = myList.Where(x => x.Contains("o")); 
// matchingList => { "foo", "foobar" }

Testez ce code @ https://rextester.com/TXDL57489

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.