Поиск По Списку Без Учета Регистра


у меня есть список testList который содержит кучу строк. Я хотел бы добавить новую строку в testList только если он еще не существует в списке. Поэтому мне нужно выполнить поиск списка без учета регистра и сделать его эффективным. Я не могу использовать Contains потому что это не учитывает корпус. Я также не хочу использовать ToUpper/ToLower по соображениям производительности. Я наткнулся на этот метод, который работает:

    if(testList.FindAll(x => x.IndexOf(keyword, 
                       StringComparison.OrdinalIgnoreCase) >= 0).Count > 0)
       Console.WriteLine("Found in list");

это работает, но он также соответствует частичным словам. Если список содержит "козу", Я не могу добавить" овес", потому что он утверждает, что" овес " уже есть в списке. Есть ли способ эффективно искать списки без учета регистра, где слова должны точно совпадать? спасибо

6 85

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

надеюсь, что это помогает, удачи!