Поиск По Списку Без Учета Регистра
у меня есть список testList
который содержит кучу строк. Я хотел бы добавить новую строку в testList
только если он еще не существует в списке. Поэтому мне нужно выполнить поиск списка без учета регистра и сделать его эффективным. Я не могу использовать Contains
потому что это не учитывает корпус. Я также не хочу использовать ToUpper/ToLower
по соображениям производительности. Я наткнулся на этот метод, который работает:
if(testList.FindAll(x => x.IndexOf(keyword,
StringComparison.OrdinalIgnoreCase) >= 0).Count > 0)
Console.WriteLine("Found in list");
это работает, но он также соответствует частичным словам. Если список содержит "козу", Я не могу добавить" овес", потому что он утверждает, что" овес " уже есть в списке. Есть ли способ эффективно искать списки без учета регистра, где слова должны точно совпадать? спасибо
6 ответов:
вместо строки.IndexOf, используйте строку.Равно чтобы убедиться, что у вас нет частичных совпадений. Также не используйте FindAll, поскольку это проходит через каждый элемент, используйте FindIndex (он останавливается на первом он попадает).
if(testList.FindIndex(x => x.Equals(keyword, StringComparison.OrdinalIgnoreCase) ) != -1) Console.WriteLine("Found in list");
поочередно использовать некоторые методы LINQ (который также останавливается на первом он попадает)
if( testList.Any( s => s.Equals(keyword, StringComparison.OrdinalIgnoreCase) ) ) Console.WriteLine("found in list");
Я понимаю, что это старый пост, но на всякий случай кто-нибудь еще смотрит, вы можете использовать
Contains
путем предоставления нечувствительного к регистру компаратора равенства строк следующим образом:if (testList.Contains(keyword, StringComparer.OrdinalIgnoreCase)) { Console.WriteLine("Keyword Exists"); }
Это было доступно с .net 2.0 в соответствии с msdn.
на основе ответа Адама Силла выше-вот хороший метод чистых расширений для Contains... :)
///---------------------------------------------------------------------- /// <summary> /// Determines whether the specified list contains the matching string value /// </summary> /// <param name="list">The list.</param> /// <param name="value">The value to match.</param> /// <param name="ignoreCase">if set to <c>true</c> the case is ignored.</param> /// <returns> /// <c>true</c> if the specified list contais the matching string; otherwise, <c>false</c>. /// </returns> ///---------------------------------------------------------------------- public static bool Contains(this List<string> list, string value, bool ignoreCase = false) { return ignoreCase ? list.Any(s => s.Equals(value, StringComparison.OrdinalIgnoreCase)) : list.Contains(value); }
на основе ответа Лэнса Ларсена-вот метод расширения с рекомендуемой строкой.Сравните вместо строки.Равно
настоятельно рекомендуется использовать перегрузку строку.Сравните, что принимает параметр StringComparison. Эти перегрузки не только позволяют определить точное поведение сравнения, которое вы намеревались, но и сделают ваш код более читаемым для других разработчиков. [Josh Free @ BCL Team Блог]
public static bool Contains(this List<string> source, string toCheck, StringComparison comp) { return source != null && !string.IsNullOrEmpty(toCheck) && source.Any(x => string.Compare(x, toCheck, comp) == 0); }
вы проверяете, если результат IndexOf больше или равен 0, то есть начинается ли матч в любом месте в строке. Попробуйте проверить, если это равной для 0:
if (testList.FindAll(x => x.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0).Count > 0) Console.WriteLine("Found in list");
Теперь "коза" и "овес" не будут совпадать, но "коза" и " Гоа " будут. Чтобы избежать этого, вы можете сравнить длины двух строк.
чтобы избежать всех этих осложнений, вы можете использовать словарь, а не список. Они ключ будет строчной строкой, и значение будет реальные строки. Таким образом, производительность не повредит, потому что вам не нужно использовать
ToLower
для каждого сравнения, но вы все еще можете использоватьContains
.
у меня была аналогичная проблема, мне нужен был индекс элемента, но он должен был быть нечувствительным к регистру, я посмотрел в интернете в течение нескольких минут и ничего не нашел, поэтому я просто написал небольшой метод, чтобы сделать это, вот что я сделал:
private static int getCaseInvariantIndex(List<string> ItemsList, string searchItem) { List<string> lowercaselist = new List<string>(); foreach (string item in ItemsList) { lowercaselist.Add(item.ToLower()); } return lowercaselist.IndexOf(searchItem.ToLower()); }
добавьте этот код в тот же файл и назовите его так:
int index = getCaseInvariantIndexFromList(ListOfItems, itemToFind);
надеюсь, что это помогает, удачи!