web-dev-qa-db-fra.com

String.Contains () est-il plus rapide que String.IndexOf ()?

J'ai un tampon de chaîne d'environ 2000 caractères et j'ai besoin de vérifier le tampon s'il contient une chaîne spécifique.
Effectuera la vérification dans une application Web ASP.NET 2.0 pour chaque requête en ligne.

Est-ce que quelqu'un sait si la méthode String.Contains donne de meilleurs résultats que méthode String.IndexOf ?

    // 2000 characters in s1, search token in s2
    string s1 = "Many characters. The quick brown fox jumps over the lazy dog"; 
    string s2 = "fox";
    bool b;
    b = s1.Contains(s2);
    int i;
    i = s1.IndexOf(s2);

Fait amusant

109
Kb.

Contains appelle IndexOf:

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Qui appelle CompareInfo.IndexOf, Qui utilise finalement une implémentation CLR.

Si vous voulez voir comment les chaînes sont comparées dans le CLR cela vous le montrera (recherchez CaseInsensitiveCompHelper).

IndexOf(string) n'a pas d'options et Contains() utilise une comparaison ordinale (comparaison octet par octet plutôt que d'essayer d'effectuer une comparaison intelligente, par exemple, e avec é).

Donc, IndexOf sera légèrement plus rapide (en théorie), car IndexOf passe directement à une recherche de chaîne à l'aide de FindNLSString à partir de kernel32.dll (la puissance du réflecteur!).

Mis à jour pour .NET 4.0 - IndexOf n'utilise plus la comparaison ordinale et donc la méthode Contains peut être plus rapide. Voir le commentaire ci-dessous.

166
Chris S

Probablement, cela n'aura aucune importance. Lisez ce post sur Coding Horror;): http://www.codinghorror.com/blog/archives/001218.html

20
Gonzalo Quero

Contains (s2) est plusieurs fois (10 fois plus rapide sur mon ordinateur) plus rapide que IndexOf (s2) car Contains utilise StringComparison.Ordinal, qui est plus rapide que la recherche liée à la culture effectuée par IndexOf par défaut (mais cela peut changer dans .net 4.0 - http://davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx ).

Contains a exactement les mêmes performances que IndexOf (s2, StringComparison.Ordinal)> = 0 dans mes tests, mais il est plus court et clarifie votre intention.

11
ggf31416

Je gère un cas réel (contrairement à une référence synthétique)

 if("=,<=,=>,<>,<,>,!=,==,".IndexOf(tmps)>=0) {

versus

 if("=,<=,=>,<>,<,>,!=,==,".Contains(tmps)) {

C'est une partie vitale de mon système et il est exécuté 131 953 fois (merci DotTrace).

Cependant surprise choquante, le résultat est l'inverse de celui attendu

  • IndexDe 533ms.
  • Contient 266ms.

: - /

net framework 4.0 (mis à jour comme pour le 13-02-2012)

7
magallanes

En utilisant Reflector, vous pouvez voir que Contains est implémenté en utilisant IndexOf. Voici la mise en œuvre.

public bool Contains(string value)
{
   return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Donc, Contains est probablement un peu plus lent que d’appeler directement IndexOf, mais je doute que cela ait une signification pour les performances réelles.

6
Brian Rasmussen

Si vous voulez vraiment optimiser votre code micro, votre meilleure approche est toujours l'analyse comparative.

Le framework .net a une excellente implémentation de chronomètre - System.Diagnostics.Stopwatch

6
Andrew Harry

D'après une petite lecture, il apparaît que sous le capot, la méthode String.Contains appelle simplement String.IndexOf. La différence est String.Contains renvoie un booléen alors que String.IndexOf renvoie un entier avec (-1), indiquant que la sous-chaîne n'a pas été trouvée.

Je suggérerais d'écrire un petit test avec environ 100 000 itérations et de voir par vous-même. Si je devais deviner, je dirais que IndexOf est peut-être un peu plus rapide mais, comme je l'ai dit, c'est juste une supposition.

Jeff Atwood a un bon article sur les chaînes à son blog . C'est plus une question de concaténation mais peut être utile quand même.

3
Mike Roosa

Juste comme une mise à jour de ceci, j'ai fait quelques tests et fourni une chaîne de caractères assez longue, alors que Regex en parallèle est la méthode C # la plus rapide que j'ai trouvée (à condition que vous ayez plus d'un noyau, j'imagine)

Obtenir le nombre total de correspondances par exemple -

needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );

J'espère que cela t'aides!

3
gary

Utilisez une bibliothèque de référence, comme cette récente incursion de Jon Skeet pour la mesurer.

Caveat Emptor

Comme pour toutes les questions de (micro) performances, cela dépend des versions du logiciel que vous utilisez, des détails des données inspectées et du code entourant l'appel.

Comme pour toutes les questions de (micro) performances, la première étape consiste à obtenir une version en cours d’exécution facile à gérer. Ensuite, le benchmarking, le profilage et le réglage peuvent être appliqués aux goulots d'étranglement mesurés au lieu de deviner.

2
David Schmitt