Verifique se a lista contém um elemento que contém uma sequência e obtenha esse elemento

146

Enquanto procurava por uma resposta para essa pergunta, encontrei outras usando o LINQ, mas não consegui entendê-las completamente (e, portanto, implementá-las), pois não estou familiarizado com ela. O que eu gostaria, basicamente, é o seguinte:

  1. Verifique se algum elemento de uma lista contém uma sequência específica.
  2. Se isso acontecer, obtenha esse elemento.

Sinceramente, não sei como eu faria isso. O que posso pensar é isso (não está funcionando, é claro):

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

Eu sei por que não funciona:

  • myList.Contains()não retorna true, pois verificará se um elemento inteiro da lista corresponde à sequência especificada.
  • myList.IndexOf() não encontrará uma ocorrência, pois, como é o caso novamente, ele verificará se há um elemento correspondente à string.

Ainda assim, não tenho idéia de como resolver esse problema, mas acho que terei que usar o LINQ conforme sugerido em perguntas semelhantes às minhas. Dito isto, se esse for o caso aqui, eu gostaria que o respondente me explicasse o uso do LINQ no exemplo deles (como eu disse, não me importei com isso no meu tempo com C #). Agradeço desde já pessoal (e galões?).

EDIT: Eu vim com uma solução; basta percorrer a lista, verificar se o elemento atual contém a sequência e defina uma sequência igual ao elemento atual. Gostaria de saber, porém, existe uma maneira mais eficiente do que isso?

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

for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Contains(myString))
        element = myList[i];
}
Dimitris Iliadis
fonte
Como mencionei na minha resposta, os loops à moda antiga (como você tem como sua pergunta) são quase sempre mais rápidos. Mas você poderia testá-lo se se importar o suficiente.
McKay
Pode haver várias strings em sua lista contendo sua string myString. No loop atual, você obterá o último elemento. Depende de você se você deseja encontrar o primeiro ou o último, se você apenas deseja encontrar o primeiro e, em seguida, interrompa o ciclo depois de encontrar o item.
Habib

Respostas:

193

Você deve poder usar o Linq aqui:

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

Se você deseja simplesmente devolver o primeiro item correspondente:

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

if(match != null)
    //Do stuff
Dave Bish
fonte
+1 - Ou substitua Wherepor FirstOrDefaultseu segundo caso #myList.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString))
Habib
Ótima resposta. Apenas por curiosidade, no entanto: por que isso matchingé determinado pelo compilador ( var)? Como sei que minha lista é do tipo String, seria seguro usá string matching-lo nesse caso?
Dimitris Iliadis
1
@JimIliadis "var" e "string" significam exatamente a mesma coisa neste caso - o compilador é inteligente o suficiente para saber que o resultado pode ser apenas 'string'. var é realmente apenas uma coisa estilo de codificação (quando não estiver usando tipos anônimos)
Dave Bish
comentando sobre tópicos muito antigos, mas encontrou uma exceção nisso. Quando você usa firstordefault (), verifique se ele também pode retornar o valor padrão. então, vamos supor que você está passando uma string empy, por exemplo, mystring = "" e você não espera nada para mostrar, mas ainda assim ele exibirá o primeiro item da lista porque você selecionou firstordefault.
Desenvolvedor sujo
@DirtyDeveloper Não sei o que você quer dizer com isso - seu exemplo retornaria 'null, se não houvesse cadeias vazias na lista de destino. Você está certo se estiver tentando usar FirstOrDefault () em um tipo de estrutura, por exemplo, List <int> - FirstOrDefault () retornará '0' e não será nulo - no entanto, a pergunta era especificamente sobre strings
Dave Bish
29

A resposta básica é: você precisa percorrer o loop e verificar se algum elemento contém a sequência especificada. Então, digamos que o código é:

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

O código equivalente, mas conciso, é:

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

Aqui, x é um parâmetro que age como "item" no código acima.

userda
fonte
12
string result = myList.FirstOrDefault(x => x == myString)
if(result != null)
{
  //found
}
Chris
fonte
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;
    }
}

Loops à moda antiga são quase sempre os mais rápidos.

McKay
fonte
Desde que eu busco eficiência, você está sugerindo que esse método seja mais rápido (portanto, mais eficiente)?
Dimitris Iliadis
2
Ainda não o testei, mas acho que isso seria mais rápido. Somente exige apenas uma passagem pela lista, até encontrar algo e sair mais cedo (como as opções do Linq podem ser bem escritas), não possui a sobrecarga de chamada de método do linq ou a sobrecarga de lambda do linq. Não que essas sejam grandes causas de preocupação, mas podem causar algum impacto no desempenho.
21413 McKay
Por que não usar List.Equals ()?
F8ER 20/01/19
@ V.7 Porque ele só quer saber se um item da lista contém uma subcadeia. list.equals não é a ferramenta correta para o trabalho ["abc", "def", "ghi"] contém "oi" da maneira que o OP o descreve. list.equals nem aceita os tipos de dados corretos.
McKay
6

Se você deseja uma lista de cadeias contendo sua cadeia:

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

Outra opção é usar o Linq FirstOrDefault

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

Lembre-se de que o Containsmétodo diferencia maiúsculas de minúsculas.

Alessandro D'Andria
fonte
1
Bom lembrete sobre o caso sensível, implementar StringComparison.InvariantCultureIgnoreCase
JoshYates1980
2

Você pode usar o FirstOrDefaultmétodo de extensão do Linq :

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

Isso retornará o elemento fist que contém a substring myStringou nullse nenhum elemento for encontrado.

Se tudo o que você precisa é o índice, use o método List<T>da classe FindIndex:

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

Isso retornará o índice do elemento fist que contém a substring myStringou -1se nenhum elemento for encontrado.

pswg
fonte
2

Muitas boas respostas aqui, mas eu uso uma simples usando Existe , como abaixo:

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);
}
Todos
fonte
2

Você deve poder usar algo como isto, funcionou bem para mim:

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

ou algo assim, se você precisar procurar onde não corresponde.

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

você pode usar

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

O LINQ fornece recursos para "consultar" qualquer coleção de dados. Você pode usar a sintaxe como uma consulta ao banco de dados (selecione, onde, etc) em uma coleção (aqui a coleção (lista) de cadeias).

então você está fazendo como "pegue itens da lista Onde ele satisfaz uma determinada condição"

dentro de Onde você está usando uma "expressão lambda"

dizer brevemente que a expressão lambda é algo como (parâmetro de entrada => valor de retorno)

portanto, para um parâmetro "item", ele retorna "item.Contains (" required string ")". Portanto, ele retornará true se o item contiver a string e, assim, for selecionado na lista, pois satisfez a condição.

Nithin Nayagam
fonte
1

Para simplificar, use isso;

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

Como alternativa, para fazer isso com o loop for, use isto;

    for (int iterator = 0; iterator < myList.Count; iterator++)
    {
        if (myList[iterator].Contains("String Pattern"))
        {
            return myList[iterator];
        }
    }
devavx
fonte
Só para ressaltar, você perdeu um suporte final de uma das linhas de código .. se (item.Contains ( "letra"))
Alex
0

Eu não vi a opção bool em outras respostas, então espero que o código abaixo ajude alguém.

Apenas use Any()

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

É possível combinar Any, Where, First e FirstOrDefault; ou apenas coloque o predicado em qualquer um desses métodos, dependendo do que for necessário.

Provavelmente, você deve evitar o uso do First, a menos que queira ter uma exceção lançada quando nenhuma correspondência for encontrada. FirstOrDefault geralmente é a melhor opção, desde que você saiba que retornará o padrão do tipo se nenhuma correspondência for encontrada (o padrão da string é nulo, int é 0, bool é falso, 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" }

Teste este código em https://rextester.com/TXDL57489

deleb
fonte