web-dev-qa-db-fra.com

Recherche dans la liste sans distinction de casse

J'ai une liste testList qui contient un tas de chaînes. Je voudrais ajouter une nouvelle chaîne dans le testList uniquement si elle n’existe pas déjà dans la liste. Par conséquent, je dois faire une recherche de la liste sans tenir compte de la casse et la rendre efficace. Je ne peux pas utiliser Contains car cela ne prend pas en compte le boîtier. Je ne veux pas non plus utiliser ToUpper/ToLower pour des raisons de performances. Je suis tombé sur cette méthode, qui fonctionne:

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

Cela fonctionne, mais cela correspond également à des mots partiels. Si la liste contient "chèvre", je ne peux pas ajouter "avoine" car elle affirme que "avoine" figure déjà dans la liste. Existe-t-il un moyen de rechercher efficacement des listes sans tenir compte de la casse, les mots devant correspondre exactement? Merci

118
Brap

Au lieu de String.IndexOf, utilisez String.Equals pour vous assurer de ne pas avoir de correspondances partielles. De même, n'utilisez pas FindAll car cela traverse tous les éléments, utilisez FindIndex (il s'arrête sur le premier élément touché).

if(testList.FindIndex(x => x.Equals(keyword,  
    StringComparison.OrdinalIgnoreCase) ) != -1) 
    Console.WriteLine("Found in list"); 

Vous pouvez également utiliser des méthodes LINQ (qui s’arrêtent également sur la première)

if( testList.Any( s => s.Equals(keyword, StringComparison.OrdinalIgnoreCase) ) )
    Console.WriteLine("found in list");
151
Adam Sills

Je réalise que ceci est un ancien post, mais juste au cas où quelqu'un d'autre regarderait, vous pouvez utiliser Contains en fournissant la chaîne insensible à la casse comparateur d'égalité comme ceci:

if (testList.Contains(keyword, StringComparer.OrdinalIgnoreCase))
{
    Console.WriteLine("Keyword Exists");
}

Ceci est disponible depuis .net 2.0 selon msdn .

305
shaxby

Basé sur la réponse d'Adam Sills ci-dessus - voici une méthode de Nice clean extensions pour 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);
}

Vous pouvez utiliser StringComparer:

    var list = new List<string>();
    list.Add("cat");
    list.Add("dog");
    list.Add("moth");

    if (list.Contains("MOTH", StringComparer.OrdinalIgnoreCase))
    {
        Console.WriteLine("found");
    }
4
jlo-gmail

Basé sur la réponse de Lance Larsen - voici une méthode d’extension avec le string recommandé.Compare au lieu de string.Equals

Il est fortement recommandé d'utiliser une surcharge de String.Compare qui utilise un paramètre StringComparison. Non seulement ces surcharges vous permettent-elles de définir le comportement de comparaison exact que vous vouliez, mais leur utilisation rendra également votre code plus lisible par d'autres développeurs. [ Josh Free @ Blog de l'équipe BCL ]

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);
}
1
dontbyteme

J'ai eu un problème similaire, j'avais besoin de l'index de l'article mais il devait être insensible à la casse, j'ai regardé le Web pendant quelques minutes et je n'ai rien trouvé, alors j'ai juste écrit une petite méthode pour le faire, voici ce que j'ai fait:

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

Ajoutez ce code dans le même fichier et appelez-le comme ceci:

int index = getCaseInvariantIndexFromList(ListOfItems, itemToFind);

En espérant que ça aide, bonne chance!

0
Monkey in Pajamas

Vous vérifiez si le résultat de IndexOf est supérieur ou égal à 0, ce qui signifie que la correspondance commence n'importe où dans la chaîne. Essayez de vérifier si c'est égal à 0:

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

Maintenant, "chèvre" et "avoine" ne correspondront pas, mais "chèvre" et "goa" le seront. Pour éviter cela, vous pouvez comparer les longueurs des deux chaînes.

Pour éviter toute cette complication, vous pouvez utiliser un dictionnaire au lieu d'une liste. La clé serait la chaîne en minuscule et la valeur, la chaîne réelle. De cette façon, les performances ne sont pas gênées, car vous n'avez pas à utiliser ToLower pour chaque comparaison, mais vous pouvez toujours utiliser Contains.

0
Ilya Kogan