IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

[TStringList] Optimisation du IndexOf ?


Sujet :

Delphi

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Par défaut [TStringList] Optimisation du IndexOf ?
    Bonjour à tous,

    Je cherche un moyen d'aller plus vite dans la recherche d'une chaine dans une TStringList ?

    Possible ou pas ?

    Amicalement,
    Bruno

  2. #2
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 236
    Par défaut
    Ta liste est triée ?

    Si oui -> Voir le forum algorythme pour trouver un algorythme de recherche, je sais que la recherche dycotomique (pas sur de l'écriture) est assez rapide.

    Si non -> Tu ne feras surement pas mieux, mais rien ne t'empeche d'aller sur le forum algo ^^
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  3. #3
    Membre Expert
    Avatar de Clorish
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    2 474
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 2 474
    Par défaut
    Dans le cas de liste non triees, on peut deja creer une serie de tableaux contenant les Index des chaines de la StringList, regrouppés par taille de la chaine.

    Lors de l'ajout d'une chaine dans la StringList, on recupere son Index et on l'ajoute dans la liste des chaines de Length(s) caracteres soit List[Length(s)]

    Apres il suffit de parcourir list[i] pour recuperer les index (list[i][j]) et donc comparer uniquement les chaines qui ont la meme taille.

    On peut aussi se baser sur un code unique (md5, crc32) qui lui sera dans une liste triée, dont la recherche se fera par dichotomie ou tout autre alogos de recherche sur tableaux triés.
    [Edit] : Autant trier directement le tableau de base

    Quoi qu'il en soit, toute solution necessitera je pense au moins une initialisation : Tri, generation de matrices/tableaux de recherche, etc....

  4. #4
    Membre éprouvé
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Par défaut
    Bonjour,

    Tu peux jeter également un coup d'oeil à THashedStringList qui est fait pour une recherche plus rapide sur des listes triées.
    Section Delphi
    La mine d'or: La FAQ, les Sources

    Un développement compliqué paraitra simple pour l'utilisateur, frustrant non ?
    Notre revanche ? l'inverse est aussi vrai ;-)

  5. #5
    Membre émérite
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Par défaut
    Oh ! Des shadocks !

    Juste pour information : une TStringList triée utilise déjà la recherche dichotomique.

    Extrait de la VCL :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    function TStringList.Find(const S: string; var Index: Integer): Boolean;
    var
      L, H, I, C: Integer;
    begin
      Result := False;
      L := 0;
      H := FCount - 1;
      while L <= H do
      begin
        I := (L + H) shr 1;
        C := CompareStrings(FList^[I].FString, S);
        if C < 0 then L := I + 1 else
        begin
          H := I - 1;
          if C = 0 then
          begin
            Result := True;
            if Duplicates <> dupAccept then L := I;
          end;
        end;
      end;
      Index := L;
    end;
     
    //...
     
    function TStringList.IndexOf(const S: string): Integer;
    begin
      if not Sorted then Result := inherited IndexOf(S) else
        if not Find(S, Result) then Result := -1;
    end;

  6. #6
    Membre Expert
    Avatar de Clorish
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    2 474
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 2 474
    Par défaut
    Citation Envoyé par CapJack
    Juste pour information : une TStringList triée utilise déjà la recherche dichotomique.
    Mais etais-ce la methode la plus rapide possible ?

  7. #7
    Membre émérite
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Par défaut
    D'un point de vue algorithmique, oui : c'est en O(log n), il n'y a pas plus rapide.

    Maintenant, il est vrai qu'on peut multiplier la vitesse du traitement par un coefficient constant, en effectuant le traitement plutôt sur des valeurs entières que sur les chaînes elle-même, mais celà devient très compliqué car il faut alors que ce soient les valeurs de hash elle-même qui soient triées.

    Pourquoi pas, mais le jeu en vaut-il la chandelle ?

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Par défaut
    Bonjour à tous,

    tout d'abord merci pour vos réponses, ensuite en recherchant sur le forum j'ai trouvé un post qui parle de remplacer la TStringList par un TClientDataSet mais j'avoue que je n'ai pas encore regardé comment faire. (Ici)

    Au final je crois que cela va être dur de faire mieux, donc peut etre revoir plus en amont dans mon traitement.

    Amitiés,
    Bruno

  9. #9
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Par défaut
    Bonjour,

    Voiçi un fonction qui renvoie le nombre d'occurences, d'un mot ou d'un sous-mot (préfixe, suffixe, ou médiane), présentes dans une StringList elle opère donc en plein-texte et ne nécessite donc pas de Splitter le texte au préalable (tenir compte de cet aspect pour apprécier les différences dans les temps d'exécution). Elle n'est pas basée sur le principe de ne comparer que les chaines qui ont la même taille mais sur le fait qu'il est intutile de comparer lorsque dans l'avancement on recontre un caractère de texte différent du 1er caractère du mot-cherché et pour accélérer la manip les recherches s'effectuent dans un MemoryStream.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    J'ai supprimé ce bout de code car il était plombé par une lourdeur. 
    Une autre version répondant grosso-modo au même descriptif est en cours de cogitation.
    ... bien entendu cette fonction a ses limites car si on cherche le mot entier 'ami' et qu'elle rencontre 'les amibes' ou 'un beau camion' elle en tient compte dans le comptage, par contre on peut la modifier pour ne repérer que des mots complets suivis d'un espace ou d'un caractère de fin-de-ligne, ou encore pour gommer le problème des Majuscules/minuscules si on cherche 'ami' et que le texte inclut 'Ami' vu notamment que dans les textes allemands les germains mettent des majuscules même en plein milieu de leurs phrases ... à discuter car on peut également mettre tout en majuscules ou en minuscules dès la phase de capture des textes ou juste après.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  10. #10
    Expert confirmé Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Par défaut
    Bonjour,

    De mémoire, il arrive qu'on doive remplacer le IndexOf par une fonction maison pour améliorer les performances de l'IndexOf standard qui sont en pratique dégradées par l'utilisation de l'instruction CompareStrings(FList^[i].FString, S) au lieu dune simple comparaison de chaine FList^[i].FString>S

  11. #11
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Par défaut
    Bonjour,

    L'astuce de Graffito est bonne en transformant les méthodes Find et IndexOf en fonctions "maison" : dans le cas d'une StringList avec Sorted:=true la vitesse d'exécution est multipliée par un facteur de 3,28.

    Par contre, pour Sorted:=false, comme pour ma fonction maison IndexOfSL qui remplace IndexOf
    j'ai simplement remplacé la ligne d'origine d'IndexOf "if not Sorted then Result := inherited IndexOf(S) else", comme suit :
    function IndexOfSL(SL : TStringList; const S: string): Integer;
    begin with SL do
    if not Sorted then Result := SL.IndexOf(S) else
    if not FindSL(SL,S, Result) then Result := -1;
    end;
    ... en conséquence de ceci, dans le cas de Sorted:=false ma fonction utilise le IndexOf de la version standard avec laquelle, dans les mêmes conditions d'essais de vitesse, le temps d'exécution est multiplié par 216 !!.
    ... mais il y a peut être une autre manière de faire cette fonction maison en traduisant autrement la ligne "if not Sorted then Result := inherited IndexOf(S) else" pour éviter d'hériter des lenteurs de la version standard ?...

    P.S : temps d'éxécution comparatifs :
    IndexOf version standard : 146 ms avec Sorted:=false et 2,20 ms avec Sorted:=true.
    IndexOfSL version maison : 145 ms avec Sorted:=false et 0,67 avec Sorted:=true. (avec Pentium III à 1,13 Ghz)
    Tests effectués en cherchant 500 fois l'index du mot 'ZFin' situé à la fin d'une StringList de 500 lignes égales à S:='texte bidon pour tests' avec bien entendu Duplicates:=DupAccept.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  12. #12
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 089
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 089
    Par défaut
    Sinon, il y a une façon élégante, faire un objet qui surcharge la classe TStringList et redéfinie la méthode virtuelle CompareStrings pour l'implémenter en > au lieu des API win/Linux ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  13. #13
    Membre émérite
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Par défaut
    Vous allez dire que je pinaille, mais c'est une question de principe.

    Citation Envoyé par Gilbert Geyer
    L'astuce de Graffito est bonne en transformant les méthodes Find et IndexOf en fonctions "maison" : dans le cas d'une StringList avec Sorted:=true la vitesse d'exécution est multipliée par un facteur de 3,28.
    Les vitesses des deux algorithmes sont effectivement proportionnelles : on peut donc bien dire que l'une est n fois plus rapide que l'autre. Attention cependant : contrairement à CompareString, la comparaison directe ne traitera pas correctement les caractères accentués ! Par exemple, "Chêne" se retrouve après "Cher"... alors qu'avec CompareStrings, le résultat est correct : ce n'est pas pour rien qu'elle met plus de temps.

    Même observation pour les bons conseils menant à un remplacement des fonctions API par des fonctions maisons... en outre, les règles de comparaison changent suivant les langues européennes. C'est à la charge de l'OS de détecter les bons paramètres et les bonnes méthodes.

    Citation Envoyé par Gilbert Geyer
    ... en conséquence de ceci, dans le cas de Sorted:=false ma fonction utilise le IndexOf de la version standard avec laquelle, dans les mêmes conditions d'essais de vitesse, le temps d'exécution est multiplié par 216 !!.
    Alors là par contre, ça me fait bondir, car tu compare un algorithme en O(log n) avec un algorithme en O(n) : il n'y a donc pas poportionnalité !

  14. #14
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Par défaut
    Bonjour,

    CapJack a écrit :
    Vous allez dire que je pinaille,
    ... absolument pas, car peut-on faire de la micro sans avoir à pinailler et où le moindre grain de sable peut bloquer le shmilblik ?

    CapJack a écrit :
    la comparaison directe ne traitera pas correctement les caractères accentués
    ... exact, reste à savoir si Bruno13 a besoin de conserver les caractères accentués ou s'il n'aurait pas intérêt à convertir tous ses textes dès leur capture entièrement en majuscules non accentuées ce qui pourrait par la même occase éviter des problèmes de différences entre deux mêmes mots dont l'un figure en début de phrase avec une majuscule et le même qu'on retrouve au milieu d'une phrase tout en minuscules car l'objectif de Bruno est davantage de dégager les concepts dominants développés dans texte que les particularismes du graphisme des caractères. Mais il revient à Bruno de nous clarifier son cahier de charge à ce sujet.

    En écho à mon "le temps d'exécution est multiplié par 216 !!", CapJack a écrit :
    Alors là par contre, ça me fait bondir, car tu compare un algorithme en O(log n) avec un algorithme en O(n) : il n'y a donc pas poportionnalité !
    ... moi ça ne me fait pas bondir ... car 145/0,67 ça fait bien 216 et je compare deux temps obtenus pour un même résultat avec deux techniques qui sont forcément différentes, bigre, sinon il n'y aurait aucune raison de comparer des temps obtenus dans les mêmes conditions d'essai par la même technique.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  15. #15
    Membre émérite
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Par défaut
    Citation Envoyé par Gilbert Geyer
    ... moi ça ne me fait pas bondir ... car 145/0,67 ça fait bien 216 et je compare deux temps obtenus pour un même résultat avec deux techniques qui sont forcément différentes, bigre, sinon il n'y aurait aucune raison de comparer des temps obtenus dans les mêmes conditions d'essai par la même technique.
    J'ai dû mal m'expliquer : quand on dit "le temps d'exécution est multiplié par n" sans préciser les conditions de l'expérience, c'est-à-dire ici le nombre d'éléments comparés, celà signifie implicitement et sans ambiguïté qu'on considère ce rapport de proportionnalité comme toujours valable : or, c'est faux : le rapport trouvé, 216, n'est pas constant, et dépend du nombre d'éléments. En effet, l'une des fonctions IndexOf parcourt tous les éléments, O(n) donc, tandis que l'autre est en O(log n). Essaie, et tu verras.

    Si tu avais précisé le nombre d'éléments utilisé pour l'expérimentation, je n'aurais alors effectivement pas relevé, car le contexte eût été différent.

    Pour ce qui est de la conclusion ironique, c'est très amusant, mais tu constateras que personnellement, je m'abstiens de ce genre de style sur ce forum, car il est parfois difficile de comprendre ce que l'autre veut dire, et souvent facile de le prendre pour un idiot parce qu'on a soit-même raté quelque chose.

  16. #16
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Par défaut
    CapJack a écrit :
    quand on dit "le temps d'exécution est multiplié par n" sans préciser les conditions de l'expérience, c'est-à-dire ici le nombre d'éléments comparés, ...
    ... le P.S. de la fin de mon message d'hier 18h22 précise bien les conditions des tests, en voici un copier-coller :
    Tests effectués en cherchant 500 fois l'index du mot 'ZFin' situé à la fin d'une StringList de 500 lignes égales à S:='texte bidon pour tests' avec bien entendu Duplicates:=DupAccept.
    ... et j'ai ajouté ce P.S avant d'envoyer le post sinon il y aurait une date de dernière modification.

    CapJack a écrit : Pour ce qui est de la conclusion ironique, c'est très amusant, mais tu constateras ...
    ... là t'as absolument raison il faut tenir compte de la sensibililté des interlocuteurs, car la fin de ma phrase après le bigre qui marque l'étonnement peut effectivement paraître ironique ... mais cela me donne une idée : pour conserver une touche d'humour suffit que je le dirige explicitement vers moi-même.

    A propos de :
    En effet, l'une des fonctions IndexOf parcourt tous les éléments, O(n) donc, tandis que l'autre est en O(log n).
    ... en transformant la fonction Find standard je me suis rendu compte en plus qu'elle ne parcourt jamais plus que la moitié des éléments vu qu'elle n'est appelée par IndexOf que pour des listes triées et que dans ce cas en attaquant les comparaisons par le milieu de liste il lui suffit suite à la première comparaison d'incrémenter soit en direction du début soit en direction de la fin... ce qui donne même du O(log n) divisé par deux ... Par contre c'est astucieux car si on cherche un mot situé pile au milieu de la liste la réponse doit être quasi-instantanée. Ouf! Heureusement que dans mes tests j'aie utilisé pour les recherches le mot 'ZFin' situé systématiquement en fin de liste.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

Discussions similaires

  1. Optimisation de votre SGBDR et de vos requêtes...
    Par SQLpro dans le forum Langage SQL
    Réponses: 35
    Dernier message: 11/01/2013, 11h49
  2. delete string delimiter optimisation TStringList LineBreak
    Par ouiouioui dans le forum Débuter
    Réponses: 9
    Dernier message: 21/02/2010, 17h23
  3. [langage]Problème de temps de lecture, optimisation
    Par And_the_problem_is dans le forum Langage
    Réponses: 2
    Dernier message: 08/01/2003, 08h47
  4. TStringList
    Par giaco dans le forum Composants VCL
    Réponses: 3
    Dernier message: 17/09/2002, 13h50
  5. [langage] Optimiser la lecture d'un fichier
    Par And_the_problem_is dans le forum Langage
    Réponses: 2
    Dernier message: 11/06/2002, 10h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo