Controlla se l'elenco contiene elementi che contengono una stringa e ottieni quell'elemento


146

Durante la ricerca di una risposta a questa domanda, mi sono imbattuto in altri simili utilizzando LINQ ma non sono stato in grado di comprenderli pienamente (e quindi implementarli), poiché non ne ho familiarità. Quello che vorrei, in sostanza, è questo:

  1. Controlla se qualche elemento di un elenco contiene una stringa specifica.
  2. In tal caso, ottieni quell'elemento.

Onestamente non so come farei per farlo. Quello che posso trovare è questo (non funziona, ovviamente):

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

So PERCHÉ non funziona:

  • myList.Contains()non ritorna true, poiché verificherà se un intero elemento dell'elenco corrisponde alla stringa specificata.
  • myList.IndexOf() non troverà una ricorrenza, poiché, come accade di nuovo, verificherà la presenza di un elemento corrispondente alla stringa.

Tuttavia, non ho idea di come risolvere questo problema, ma immagino che dovrò usare LINQ come suggerito in domande simili alle mie. Detto questo, se è il caso qui, vorrei che il rispondente mi spiegasse l'uso di LINQ nel loro esempio (come ho detto, non mi sono preoccupato ai miei tempi con C #). Grazie in anticipo ragazzi (e ragazze?).

EDIT: ho trovato una soluzione; basta scorrere l'elenco, verificare se l'elemento corrente contiene la stringa e quindi impostare una stringa uguale all'elemento corrente. Mi chiedo, però, esiste un modo più efficiente di questo?

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

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

come menziono nella mia risposta, i vecchi loop di moda (come te hanno come domanda) sono quasi sempre i più veloci. Ma potresti perfezionarlo se ti interessa abbastanza.
McKay,

Potrebbero esserci più stringhe nell'elenco che contengono la stringa myString, nel tuo ciclo corrente otterrai l'ultimo elemento. Dipende da te se vuoi trovare il primo o l'ultimo, se vuoi solo trovare il primo, quindi interrompere il ciclo dopo aver trovato l'oggetto.
Habib,

Risposte:


193

Dovresti essere in grado di utilizzare Linq qui:

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

Se desideri semplicemente restituire il primo articolo corrispondente:

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

if(match != null)
    //Do stuff

+1 - O sostituisci Wherecon FirstOrDefaultnel secondo casomyList.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString))
Habib

Bella risposta. Solo per curiosità, però: perché è matchingdeterminato dal compilatore ( var)? Dato che so che il mio elenco è di tipo String, sarebbe sicuro usarlo string matchingin questo caso?
Dimitris Iliadis,

1
@JimIliadis "var" e "string" significano esattamente la stessa cosa in questo caso - il compilatore è abbastanza intelligente da sapere che il risultato può essere solo 'string'. var è davvero solo una cosa di stile di codifica (quando non si usano tipi anonimi)
Dave Bish,

commentando il thread troppo vecchio, ma ho trovato un'eccezione su questo. quando usi firstordefault () assicurati che possa restituire anche il valore predefinito. quindi, supponiamo che tu stia passando una stringa empy, cioè mystring = "" e non ti aspetti di mostrare nulla, ma mostrerà comunque il primo elemento della lista perché hai selezionato firstordefault.
Sviluppatore sporco

@DirtyDeveloper Non sei sicuro di cosa intendi con questo - il tuo esempio restituirà 'null, se non ci fossero stringhe vuote nell'elenco di destinazione. Hai ragione se stai tentando di usare FirstOrDefault () su un tipo di struttura, ad esempio List <int> - FirstOrDefault () restituirà '0' e non null - tuttavia, la domanda riguardava specificamente le stringhe
Dave Bish,

29

La risposta di base è: è necessario scorrere ripetutamente il ciclo e verificare che qualsiasi elemento contenga la stringa specificata. Quindi, supponiamo che il codice sia:

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

Il codice equivalente, ma conciso, è:

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

Qui, x è un parametro che si comporta come "item" nel codice sopra.


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

I vecchi loop di moda sono quasi sempre i più veloci.


Dal momento che cerco l'efficienza, stai suggerendo che questo metodo è più veloce (quindi, più efficiente)?
Dimitris Iliadis,

2
Non ho testato perf, ma immagino che questo sarebbe più veloce. Richiede sempre e solo un passaggio attraverso l'elenco, fino a quando non trova qualcosa e scoppia in anticipo (come le opzioni di Linq potrebbero fare se scritte bene), non ha il metodo di invocazione del metodo di linq, né il sovraccarico lambda di linq. Non che queste siano enormi cause di preoccupazione, ma possono causare un certo calo delle prestazioni.
McKay,

Perché non usare List.Equals ()?
F8ER,

@ V.7 Perché vuole solo sapere se un elemento nell'elenco contiene una sottostringa. list.equals non è lo strumento corretto per il lavoro ["abc", "def", "ghi"] contiene "hi" nel modo in cui l'OP lo descrive. list.equals non accetta nemmeno i tipi di dati corretti.
McKay,

6

Se vuoi un elenco di stringhe contenenti la tua stringa:

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

Un'altra opzione è utilizzare Linq FirstOrDefault

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

Tieni presente che il Containsmetodo fa distinzione tra maiuscole e minuscole.


1
Buon promemoria sulla distinzione tra maiuscole e minuscole, implementa StringComparison.InvariantCultureIgnoreCase
JoshYates1980,

2

È possibile utilizzare il FirstOrDefaultmetodo di estensione Linq :

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

Ciò restituirà l'elemento pugno che contiene la sottostringa myStringo nullse non viene trovato tale elemento.

Se tutto ciò di cui hai bisogno è l'indice, usa il metodo List<T>della classe FindIndex:

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

Ciò restituirà l'indice dell'elemento pugno che contiene la sottostringa myStringo -1se non viene trovato tale elemento.


2

Molte buone risposte qui, ma ne uso una semplice usando Exists , come di seguito:

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

Dovresti essere in grado di usare qualcosa del genere, ha funzionato bene per me:

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

o qualcosa del genere, se hai bisogno di guardare dove non corrisponde.

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

1

Puoi usare

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

LINQ offre funzionalità per "interrogare" qualsiasi raccolta di dati. È possibile utilizzare la sintassi come una query di database (selezionare, dove, ecc.) In una raccolta (qui la raccolta (elenco) di stringhe).

quindi stai facendo come "prendimi elementi dall'elenco Dove soddisfa una determinata condizione"

all'interno del punto in cui stai utilizzando una "espressione lambda"

dire brevemente l'espressione lambda è qualcosa di simile (parametro di input => valore restituito)

quindi per un parametro "item", restituisce "item.Contains (" string richiesta ")". Quindi restituisce true se l'elemento contiene la stringa e quindi viene selezionato dall'elenco poiché ha soddisfatto la condizione.


1

Per semplicità, usa questo;

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

In alternativa, per fare ciò con for loop, usare questo;

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

Giusto per sottolineare, hai perso una parentesi quadra su una delle righe di codice .. if (item.Contains ("Search Term"))
Alex

0

Non ho visto l'opzione bool in altre risposte, quindi spero che sotto il codice possa aiutare qualcuno.

Basta usare Any()

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

0

È possibile combinare Any, Where, First e FirstOrDefault; o semplicemente posizionare il predicato in uno di questi metodi a seconda di ciò che è necessario.

Probabilmente dovresti evitare di usare First a meno che tu non voglia generare un'eccezione quando non viene trovata alcuna corrispondenza. FirstOrDefault è di solito l'opzione migliore fintanto che sai che restituirà l'impostazione predefinita del tipo se non viene trovata alcuna corrispondenza (l'impostazione predefinita della stringa è nulla, int è 0, valore bool è falso, ecc.).

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

Prova questo codice @ https://rextester.com/TXDL57489

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.