122 votes

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

J'ai un tampon de chaîne d'environ 2000 caractères et je dois vérifier si le tampon contient une chaîne spécifique.
Effectue la vérification dans une application Web ASP.NET 2.0 pour chaque requête Web.

Quelqu'un sait-il si le Méthode String.Contains est plus performant 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

16 votes

Si vous avez besoin de faire cela un milliard de fois par requête web, je commencerais à jeter un coup d'oeil à des trucs comme ça. Dans tous les autres cas, je ne m'en préoccuperais pas, car le temps passé dans l'une ou l'autre méthode sera très probablement incroyablement insignifiant par rapport à la réception de la requête HTTP en premier lieu.

2 votes

L'une des clés de l'optimisation est de tester au lieu de supposer, car cela peut dépendre de nombreux facteurs tels que la version .NET, le système d'exploitation, le matériel, la variation de l'entrée, etc. Dans de nombreux cas, les résultats des tests effectués par d'autres peuvent être très différents sur votre système.

187voto

Chris S Points 32376

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 de caractères sont comparées dans le CLR cela vous montrera (cherchez CaseInsensitiveCompHelper ).

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

Alors IndexOf sera marginalement plus rapide (en théorie) que IndexOf passe directement à une recherche de chaîne de caractères en utilisant FindNLSString de kernel32.dll (la puissance du réflecteur !).

Mise à jour pour .NET 4.0 - IndexOf n'utilise plus la comparaison ordinale et les contenants peuvent donc être plus rapides. Voir le commentaire ci-dessous.

3 votes

Cette réponse est loin d'être correcte, regardez ici. stackoverflow.com/posts/498880/revisions pour l'explication

64 votes

Ma réponse a 7 ans et est basée sur le cadre .NET 2. Version 4 IndexOf() utilise en effet StringComparison.CurrentCulture et Contains() utilise StringComparison.Ordinal ce qui sera plus rapide. Mais en réalité, les différences de vitesse dont nous parlons sont infimes - l'essentiel est que l'un appelle l'autre, et que Contains soit plus lisible si vous n'avez pas besoin de l'index. En d'autres termes, ne vous en préoccupez pas.

4 votes

Je l'ai essayé aujourd'hui sur un fichier texte de 1,3 Go. Entre autres, chaque ligne est vérifiée pour l'existence d'un caractère '@'. 17.000.000 appels à Contains/IndexOf sont effectués. Résultat : 12,5 secondes pour tous les appels à Contains(), 2,5 secondes pour tous les appels à IndexOf() => IndexOf est 5 fois plus rapide ! (.Net 4.8)

22voto

Gonzalo Quero Points 2492

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

4 votes

On fait de la lèche au patron, n'est-ce pas ? ? :D Vous avez raison cependant, comparé au temps pris pour servir une requête http, rechercher une courte chaîne de caractères, une fois, n'est pas significatif.

0 votes

Une lecture très divertissante, mais cela me dérange que sa plainte initiale avec la concaténation est l'utilisation de la mémoire, puis il ne teste que le temps passé avec les différentes façons de combiner les chaînes de caractères.

12voto

ggf31416 Points 2060

Contains(s2) est plusieurs fois (dans mon ordinateur 10 fois) plus rapide que IndexOf(s2) parce que Contains utilise StringComparison.Ordinal qui est plus rapide que la recherche sensible à la culture que IndexOf fait 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 rend votre intention claire.

2 votes

Les changements dans .NET 4.0 ont apparemment été annulés avant la sortie de la version RTM, donc je ne me fierais pas trop à cet article. blogs.msdn.com/bclteam/archive/2008/11/04/

6voto

Brian Rasmussen Points 68853

En utilisant Reflector, vous pouvez voir que Contains est implémenté en utilisant IndexOf. Voici l'implémentation.

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

Ainsi, Contains est probablement un peu plus lent que l'appel direct à IndexOf, mais je doute que cela ait une quelconque incidence sur les performances réelles.

1 votes

Oui, mais pour utiliser indexof comme un bool, il devrait faire la comparaison en dehors de la fonction. Cela donnerait très probablement le même résultat que Contains, n'est-ce pas ?

1 votes

Probablement, mais vous économisez un appel de méthode (à moins qu'il ne puisse être inlined). Comme je l'ai dit, cela ne sera probablement jamais significatif.

6voto

Andrew Harry Points 5488

Si vous voulez vraiment micro-optimiser votre code, la meilleure approche est toujours le benchmarking.

Le cadre .net dispose d'une excellente implémentation du chronomètre - System.Diagnostics.Chronomètre

0 votes

C'est le meilleur mais si vous voulez une approche rapide, appuyez simplement sur le bouton pause dans une session de débogage. Le contrôle du code est susceptible de s'arrêter dans la partie la plus lente environ 50 % du temps .

2 votes

@JeremyThompson répétez la méthode "pause debug" au moins 10 fois et vous aurez un profiler.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X