Проверьте, содержит ли список элемент, содержащий строку, и получите этот элемент

149

В поисках ответа на этот вопрос я столкнулся с похожими, использующими LINQ, но я не смог полностью их понять (и, следовательно, реализовать их), поскольку я не знаком с этим. В основном я хотел бы вот что:

  1. Проверьте, содержит ли какой-либо элемент списка определенную строку.
  2. Если да, возьмите этот элемент.

Честно говоря, не знаю, как бы я это сделал. Что я могу придумать, так это (не работает, конечно):

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

Я знаю, ПОЧЕМУ не работает:

  • myList.Contains()не возвращается true, поскольку он проверяет, соответствует ли весь элемент списка указанной мной строке.
  • myList.IndexOf() не найдет вхождения, поскольку, как и в этом случае, он будет проверять элемент, соответствующий строке.

Тем не менее, я понятия не имею, как решить эту проблему, но полагаю, что мне придется использовать LINQ, как предлагалось в вопросах, аналогичных моему. При этом, если это так, я бы хотел, чтобы отвечающий объяснил мне использование LINQ в своем примере (как я уже сказал, я не беспокоился об этом в свое время с C #). Заранее спасибо, ребята (а девчонки?).

РЕДАКТИРОВАТЬ: я нашел решение; просто прокрутите список, проверьте, содержит ли текущий элемент строку, а затем установите строку, равную текущему элементу. Однако мне интересно, есть ли более эффективный способ, чем этот?

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

for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Contains(myString))
        element = myList[i];
}
Димитрис Илиадис
источник
как я упоминал в своем ответе, старые модные петли (например, в вашем вопросе) почти всегда самые быстрые. Но вы можете проверить это, если будете достаточно внимательны.
McKay
В вашем списке может быть несколько строк, содержащих вашу строку myString, в текущем цикле вы получите последний элемент. От вас зависит, хотите ли вы найти первый или последний, если вы просто хотите найти первый, а затем прервите цикл после нахождения элемента.
Хабиб

Ответы:

198

Здесь вы сможете использовать Linq:

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

Если вы просто хотите вернуть первый соответствующий элемент:

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

if(match != null)
    //Do stuff
Дэйв Биш
источник
+1 - Или замените Whereна FirstOrDefaultво втором случаеmyList.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString))
Хабиб
Отличный ответ. Но из любопытства: почему это matchingопределяется компилятором ( var)? Поскольку я знаю, что мой список относится к типу String, будет ли его безопасно использовать string matchingв этом случае?
Димитрис Илиадис
1
@JimIliadis «var» и «string» в этом случае означают одно и то же - компилятор достаточно умен, чтобы знать, что результатом может быть только «строка». var - это действительно просто стиль кодирования (если не использовать анонимные типы)
Дэйв Биш,
комментируя слишком старую ветку, но обнаружил одно исключение. при использовании firstordefault () убедитесь, что он также может вернуть значение по умолчанию. Итак, предположим, что вы передаете пустую строку, т.е. mystring = "", и вы не ожидаете, что ничего будет отображаться, но все же будет отображаться первый элемент списка, потому что вы выбрали firstordefault.
Dirty Developer
1
"Любой" Подойдет лучше var matchvalues ​​= myList .Any (stringToCheck => stringToCheck.Contains (myString));
wilaponce
29

Основной ответ: вам нужно пройти цикл и проверить, что любой элемент содержит указанную строку. Итак, допустим, код:

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

Эквивалентный, но краткий код:

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

Здесь x - параметр, который действует как «элемент» в приведенном выше коде.

userda
источник
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;
    }
}

Петли Old Fashion почти всегда самые быстрые.

Маккей
источник
Поскольку я стремлюсь к эффективности, вы предлагаете, чтобы этот метод был быстрее (а значит, более эффективным)?
Димитрис Илиадис
2
Я не тестировал его, но думаю, что это будет быстрее. Требуется только один проход по списку, пока он не найдет что-то и не выйдет из строя раньше (как, например, параметры Linq, если они написаны правильно), не будет накладных расходов на вызов метода для linq или лямбда-накладных расходов для linq. Не то чтобы это серьезная причина для беспокойства, но может привести к некоторому снижению производительности.
McKay
Почему не использовать List.Equals ()?
F8ER
@ V.7 Потому что он только хочет знать, содержит ли один элемент в списке подстроку. list.equals не является подходящим инструментом для работы ["abc", "def", "ghi"] действительно содержит "hi" в том смысле, как его описывает OP. list.equals даже не принимает правильные типы данных.
McKay
6

Если вам нужен список строк, содержащих вашу строку:

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

Другой вариант - использовать Linq FirstOrDefault

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

Имейте в виду, что этот Containsметод чувствителен к регистру.

Алессандро Д'Андрия
источник
1
Хорошее напоминание о чувствительности к регистру: реализуйте StringComparison.InvariantCultureIgnoreCase
JoshYates1980,
3

Здесь много хороших ответов, но я использую простой, используя Exists , как показано ниже:

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

Вы можете использовать FirstOrDefaultметод расширения Linq :

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

Это вернет первый элемент, содержащий подстроку myString, или nullесли такой элемент не найден.

Если вам нужен только индекс, используйте метод List<T>класса FindIndex:

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

Это вернет индекс первого элемента, который содержит подстроку myString, или -1если такой элемент не найден.

pswg
источник
2

Вы должны иметь возможность использовать что-то вроде этого, у меня это сработало:

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

или что-то вроде этого, если нужно посмотреть, где не совпадает.

 var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));
Гоку
источник
1

ты можешь использовать

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

LINQ предоставляет вам возможность «запрашивать» любую коллекцию данных. Вы можете использовать синтаксис, как запрос к базе данных (выберите, где и т. Д.) В коллекции (здесь коллекция (список) строк).

так что вы делаете что-то вроде "достань мне предметы из списка, где он удовлетворяет заданному условию"

внутри Где вы используете "лямбда-выражение"

кратко сказать, что лямбда-выражение выглядит примерно так (входной параметр => возвращаемое значение)

поэтому для параметра «item» он возвращает «item.Contains (« требуемая строка »)». Таким образом, он возвращает истину, если элемент содержит строку и, таким образом, выбирается из списка, так как он удовлетворяет условию.

Нитхин Наягам
источник
1

Чтобы было проще, используйте это;

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

В качестве альтернативы, чтобы сделать это с помощью цикла for, используйте this;

    for (int iterator = 0; iterator < myList.Count; iterator++)
    {
        if (myList[iterator].Contains("String Pattern"))
        {
            return myList[iterator];
        }
    }
devavx
источник
Отметим, что вы пропустили конечную скобку в одной из строк кода .. if (item.Contains ("Search Term"))
Alex
0

Я не видел опцию bool в других ответах, поэтому надеюсь, что приведенный ниже код кому-то поможет.

Просто используйте Any()

string myString = "test";
bool exists = myList
             .Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();
Павел Чапски
источник
0

Можно комбинировать Any, Where, First и FirstOrDefault; или просто поместите предикат в любой из этих методов в зависимости от того, что необходимо.

Вероятно, вам следует избегать использования First, если вы не хотите, чтобы при отсутствии совпадения генерировалось исключение. FirstOrDefault обычно является лучшим вариантом, если вы знаете, что он вернет значение по умолчанию для типа, если совпадение не найдено (строка по умолчанию - null, int - 0, bool - false и т. Д.).

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

Протестируйте этот код @ https://rextester.com/TXDL57489

делеб
источник