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 :

Y-a-t-il plus rapide pour enlever les mots vides ?


Sujet :

Delphi

  1. #1
    Membre habitué
    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
    Points : 199
    Points
    199
    Par défaut Y-a-t-il plus rapide pour enlever les mots vides ?
    Bonjour à tous,

    Voici la suite de mes contraintes en temps d'execution pour mon programme, ici il s'agit de supprimer d'un texte les mots vides.

    Je vais essayer de tout vous donner pour que l'on puisse faire les testes identiques (du moins sans tenir compte des processeurs) :

    Voici le lien/texte à utiliser :
    http://www.american.edu/ia/cfer/report/report.html
    Voici ma fonction :
    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
    function DeleteEmptyWord2(CONST Texte, sLang: String): String;
    var
       StringListMotsDuTexteAAusculter, lMotsVides : TStringList;
       i, j : integer;
    Begin
      result:='';
      StringListMotsDuTexteAAusculter:=TStringList.Create;
      lMotsVides:=TStringList.Create;
      Try
        StringListMotsDuTexteAAusculter.Text:=Texte;
        if StringListMotsDuTexteAAusculter.Count>0 then
        Begin
          // 1. Virer les mots vides
          lMotsVides.LoadFromFile(ExtractFilePath(Application.ExeName)+'\'+cPathStopWord+'\'+sLang+'.fstw');
          for i:=0 to lMotsVides.Count-1 do
          Begin
            j :=StringListMotsDuTexteAAusculter.IndexOf(lMotsVides[i]);
            While j>=0 do
            Begin
              StringListMotsDuTexteAAusculter.Delete(j);
              j :=StringListMotsDuTexteAAusculter.IndexOf(lMotsVides[i]);
            End;
          End;
          result:=StringListMotsDuTexteAAusculter.Text;
        End;
      Finally
        lMotsVides.Free;
        StringListMotsDuTexteAAusculter.Free;
      End;
    End;
    Et voici la liste des mots vides :
    a
    about
    above
    after
    again
    against
    all
    am
    an
    and
    any
    are
    aren't
    as
    at
    be
    because
    been
    before
    being
    below
    between
    both
    but
    by
    can't
    cannot
    com
    could
    couldn't
    de
    did
    didn't
    do
    does
    doesn't
    doing
    don't
    down
    during
    each
    en
    few
    for
    from
    further
    had
    hadn't
    has
    hasn't
    have
    haven't
    having
    he
    he'd
    he'll
    he's
    her
    here
    here's
    hers
    herself
    him
    himself
    his
    how
    how's
    i
    i'd
    i'll
    i'm
    i've
    if
    in
    into
    is
    isn't
    it
    it's
    its
    itself
    la
    let's
    more
    most
    mustn't
    my
    myself
    no
    nor
    not
    of
    off
    on
    once
    only
    or
    other
    ought
    our
    ours
    ourselves
    out
    over
    own
    same
    shan't
    she
    she'd
    she'll
    she's
    should
    shouldn't
    so
    some
    such
    than
    that
    that's
    the
    their
    theirs
    them
    themselves
    then
    there
    there's
    these
    they
    they'd
    they'll
    they're
    they've
    this
    those
    through
    to
    too
    und
    under
    until
    up
    very
    was
    wasn't
    we
    we'd
    we'll
    we're
    we've
    were
    weren't
    what
    what's
    when
    when's
    where
    where's
    which
    while
    who
    who's
    whom
    why
    why's
    will
    with
    won't
    would
    wouldn't
    www
    you
    you'd
    you'll
    you're
    you've
    your
    yours
    yourself
    yourselves

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 299
    Points
    11 299
    Billets dans le blog
    6
    Par défaut
    pourrait-on voir les mots vides comme un arbre ? avec un parcours de lettre en lettre, jusqu'à arriver sur un espace (c'est sûrement réducteur, disons un caractère de ponctuation : ', ;. etc.)
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  3. #3
    Membre chevronné
    Avatar de Pierre Castelain
    Inscrit en
    Avril 2002
    Messages
    523
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 523
    Points : 1 943
    Points
    1 943
    Par défaut
    Comme l'a dit tourlourou, tu aurais certainement intérêt à changer de méthode et à construire un dictionnaire (au sens structure de données) pour améliorer le temps de recherche.
    Mais si on considère que tu veux continuer à utiliser de simples stringlists, tu peux déjà améliorer sérieusement ton code.
    1 - Au lieu de boucler sur chaque mot "vide" et rechercher une correspondance dans le texte, tu ferais mieux de faire l'inverse. Il y a de grande chance que le texte soit plus long que la liste de mots vides, la recherche ira donc plus vite dans ce sens.
    2 - Une fois le premier point réglé, tu devrais trier la liste de mots vides en positionnant la propriété Sorted de la TStringList à true. Cela aura pour effet d'améliorer le temps d'exécution de la méthode IndexOf puisqu'elle va basculer sur un algorithme de recherche dichotomique.

    Une dernière remarque, tu n'as pas indiqué comment tu passais du texte de la page web à une stringlist. Je présume que tu obtiens bien une liste de mots uniques (un mot par élément de la liste), sinon ton algorithme ne fonctionnera pas, à moins que je n'ai pas bien compris la situation.

  4. #4
    Expert éminent 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
    Points : 7 903
    Points
    7 903
    Par défaut
    Bonjour,

    2 petites remarques sur le IndexOf :
    • reprendre le code de Tstrings.IndexOf pour faire un code IndexOf en remplaçant le CompareString par une simple comparaison de chaine,
    • Trier la TstringList de mots pour que IndexOf fasse une recherche dichotomique (cf Castellain), dans ce cas il faudra reprendre le code de TstringList.find et remplacer le CompareString.
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  5. #5
    Membre habitué
    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
    Points : 199
    Points
    199
    Par défaut
    Bonjour tout le monde,

    alors j'ai suivi quelques conseils, et tout d'abord :


    Une dernière remarque, tu n'as pas indiqué comment tu passais du texte de la page web à une stringlist. Je présume que tu obtiens bien une liste de mots uniques (un mot par élément de la liste), sinon ton algorithme ne fonctionnera pas, à moins que je n'ai pas bien compris la situation.
    Oui j'ai d'abord fait un HTMLToText où la string renvoyée est du genre :
    coucou#13#10vous#13#10avez#13#10le#13#10bonjour etc...

    1 - Au lieu de boucler sur chaque mot "vide" et rechercher une correspondance dans le texte, tu ferais mieux de faire l'inverse. Il y a de grande chance que le texte soit plus long que la liste de mots vides, la recherche ira donc plus vite dans ce sens.
    Et là effectivement de plus de 2 minutes je passe à 7 secondes, c'est déjà trés bien, mais je suis sûr qu'avec les autres infos je vais pouvoir faire mieux :

    Voici la fonction :
    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 DeleteEmptyWord2(CONST Texte, sLang: String): String;
    var
       StringListMotsDuTexteAAusculter, lMotsVides : TStringList;
       i, j : integer;
    Begin
      result:='';
      StringListMotsDuTexteAAusculter:=TStringList.Create;
      lMotsVides:=TStringList.Create;
      Try
        StringListMotsDuTexteAAusculter.Text:=Texte;
     
        if StringListMotsDuTexteAAusculter.Count>0 then
        Begin
          // 1. Virer les mots vides
          lMotsVides.LoadFromFile(ExtractFilePath(Application.ExeName)+'\'+cPathStopWord+'\'+sLang+'.fstw');
          lMotsVides.Sorted := True;
     
          i:=StringListMotsDuTexteAAusculter.Count-1;
          While i>=0 do
          Begin
             while lMotsVides.IndexOf(StringListMotsDuTexteAAusculter[i])>=0 do
               StringListMotsDuTexteAAusculter.Delete(i);
             dec(i);
          End;
          result:=StringListMotsDuTexteAAusculter.Text;
        End;
      Finally
        lMotsVides.Free;
        StringListMotsDuTexteAAusculter.Free;
      End;
    End;
    Ensuite :

    * reprendre le code de Tstrings.IndexOf pour faire un code IndexOf en remplaçant le CompareString par une simple comparaison de chaine,
    Alors là j'ai besoin de votre aide car, le surclassement n'est pas ma tasse de thé.

    * Trier la TstringList de mots pour que IndexOf fasse une recherche dichotomique (cf Castellain), dans ce cas il faudra reprendre le code de TstringList.find et remplacer le CompareString.
    Impossible pour moi de faire cela car si je trie la liste des mots de la page je perds l'ordre du texte, et si je perd l'ordre du texte je perds les co-occurrences. Par contre j'ai mis la liste des mots vides à Sorted:=True;

    Merci pour vos conseils
    Bruno

  6. #6
    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
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    1) A propos de la remarque de Graffito disant "reprendre le code de Tstrings.IndexOf pour faire un code IndexOf en remplaçant le CompareString par une simple comparaison de chaine" :

    Bruno13 a écrit :
    Alors là j'ai besoin de votre aide car, le surclassement n'est pas ma tasse de thé
    ... là je ne pige plus car dans ton message du 16/07/2007, 02h40 dans une autre discussion Bruno tu m'as répondu et joint le code que tu as retenu pour remplacer la version standard de IndexOf :
    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
    ... IndexOfSL3 mais hélas chez moi je commence à croire que ce n'est pas spécialement lui qui prend du temps dans mon traitement.
    Ma liste n'est pas triée donc j'ai même pu simplifier celle-ci pour mon cas :
    
    function TKeywordList.IndexOfSL3(Item : TKeywordClass): Integer;
    var      I: Integer;
    begin
                   Result := -1;
                   I:=FItems.Count-1;
                   While I>=0 do
                   Begin
                      if Items[i].Name = Item.Name then
                      Begin
                         Result:= I;
                         EXIT;
                      End;
                      Dec(i);
                   End;
    end;
    ... on constate bien que CompareString a disparu au profit d'une recherche d'égalité de chaines
    ... en plus le choix de travailler sur des listes non triées avait été effectué dans un contexte de comparaisons de gains de vitesse sur la variante précédente d'IndexOfSL3 qui traitait aussi bien le cas de listes-triées que des listes-non-triées dont je résume ici les résultats pour ceux qui n'avaient pas participé aux autres discussions :
    A titre indicatif les temps d'exécution comparatifs avec la version standard d'IndexOf, et une liste SLTexte comportant 2000 mots non accentués du dictionnaire la boucle (for i:=0 to SLTexte.count-1 do index:=IndexOfSL3(SLTexte,SLTexte[i]) ) où l'on recherche à tour de rôle l'index de chacun des 2000 mots de la liste ont été (Pentium III à 1,13 MHz) :
    - Version standard d'IndexOf : 332 ms pour Sorted=False, et 13 ms pour Sorted=True.
    - Version [complète dichotomique et sans CompareString] d'IndexOfSL3 : 79 ms pour Sorted=False, et 6 ms pour Sorted=True.
    ... mais comme entre-temps tu as opté pour la conversion des caractères-accentués en caractères-non-accentués la version complète d'IndexOfSL3 est alors efficace même avec des listes triées et surtout avec des listes triées vu le gain de rapidité par rapport à la version standard d'IndexOf qui ré-apparaît dans ton code au début de la présente discussion.

    2) A propos de trier les listes :
    Bruno 13 a écrit : Impossible pour moi de faire cela car si je trie la liste des mots de la page je perds l'ordre du texte, et si je perd l'ordre du texte je perds les co-occurrences.
    ... Suggestion : pourquoi ne pas :
    1 ) mémoriser l'ordre initial des mots du texte lors du chargement de la liste-des-mots-de-la-page-non-triée avec maListe.AddObject(monMot,monObject) en mémorisant l'indice de monMot dans monObject,
    2) trier ensuite la liste avec maListe.Sort;
    3) confirmer cet état avec maListe.Sorted:=true; pour utiliser IndexOfSL3-version-dichotomique lors de la phase de "suppression" des mots vides où au lieu de supprimer le mot-vide avec Delete(i) tu le remplaces par une chaine vide;
    4) et après cette pseudo-suppression des mots vides tu rétablis l'ordre-initial de la liste à partir des indices-initiaux-mémorisés-dans chacun des monObject en permutant les lignes vers l'ordre-initial.
    A+

    EDIT P.S de 15h50 : Suite du point 2) : Résultats d'un test de vitesse effectué à partir d'une liste de 2000 mots sur Pentium III 1,13 GHz :
    - création d'une liste de 2000 mots avec AddObject qui mémorise l'indice-de-l'ordre-initial : mis moins de 1 ms
    - tri de cette liste avec méthode Sort : 28ms
    - rétablissement de l'ordre-initial par création d'une liste (sans Objects pour virer ensuite la liste-source et ses Objects) : mis moins de 1 ms
    Il est donc possible de trier la liste des mots et de rétablir l'ordre du texte, pour l'histoire des co-occurrences. En bref, en combinant cette possibilité avec l'utilisation d'IndexOfSL3-version-dichotomique-sur-liste-triée-de-mots-non-accentués lors de la phase de remplacement des mots vides par des chaines vides tu serais débarassé des lenteurs d'IndexOf-version-standard.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  7. #7
    Membre habitué
    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
    Points : 199
    Points
    199
    Par défaut
    Salut Gilbert,

    Oui effectivement, j'utilise bien ta version d'indexofSL3 je ne sais pas pourquoi j'ai pas percuté à ce moment là, surement la fatigue, hier j'ai laché le clavier à 5h du mat, mille excuses.

    Pour ce qui est de ta suggestion avec les maListe.AddObject(monMot,monObject) c'est une trés bonne idée, je vais essayer de mettre en place tout cela.

    Encore une fois, on s'apercoit qu'il y a mille manière de programmer une chose.

    Gracias

  8. #8
    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
    Points : 3 263
    Points
    3 263
    Par défaut
    Salut Bruno,

    Voici des bouts de code issus du micro projet utilisé lors des tous derniers tests de rétablissement de l'ordre initial après tri :
    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
    32
     
    // 1 ) Pour créer, à partir d'une Liste-source, la liste avec les indices placés dans les Objects :
    function  CreerListeAvecIndicesEnObjet(const LSOrdreIni : TStringList) : TStringList;
    var       ind : integer; // s : string;
    begin     Result:=TStringList.create;
              for ind:=0 to LSOrdreIni.count-1
               do Result.AddObject(LSOrdreIni[ind],tObject(integer(ind)));
              {for ind:=0 to LSOrdreIni.count-1 do
              begin //s:=intToStr(integer(LSOrdreIni.Objects[ind]));
                    //showMessage(s); simple vérif en phase de mise au point
              end;}
    end;
     
    //2) Pour rétablir l'ordre initial en créant une nouvelle liste à partir de la précédente mise dans le désordre entre-temps par un tri-alpha :
     
    function  RetablirOrdreInitial(const ListeSourceInd : TStringList) : TStringList;
    //        Pour ListeSourceInd qui contient dans ses Objects les indices-de-l'ordre-initial
    //        Renvoie une liste rétablie dans l'ordre initial
    var       i,indMemorise : integer;
    begin     Result:=TStringList.create;
              for i:=0 to ListeSourceInd.count-1 do
              begin // initialisation nouvelle liste et en même temps on met rien en object
                    // pour virer les objects en virant après l'appel la liste-source
                    Result.Add('');
              end;
              for i:=0 to ListeSourceInd.count-1 do
              begin // on place dans les chaines '' le mot correspondant à l'indice-initial
                    // mémorisé dans l'object
                    indMemorise:=integer(ListeSourceInd.Objects[i]);
                    Result[indMemorise]:=ListeSourceInd[i];
              end;
    end;
    ... bonnne suite, et à +.

    EDIT : P.S : tu dis "j'ai laché le clavier à 5h du mat" : fais gaffe, car à force de trop bosser on finit ou bout d'une certaine période par bosser en "mode dégradé" à rendement quasi-nul.

    EDIT 2 du 20/07 10h3: simple changement dans le code du nom de la const LSOrdreIni : TStringList (plus parlant)
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  9. #9
    Membre habitué
    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
    Points : 199
    Points
    199
    Par défaut
    Salut Gilbert,

    Bon pour l'instant j'ai toujours environ 7 secondes en utilsant une listObject.
    Mais je dois voir si j'ai pas fait quelques betises car je fais actuellement mille choses à la fois.

    suite au prochain post.

    Amitiés,
    Bruno

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    624
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 624
    Points : 754
    Points
    754
    Par défaut
    Faites gaffe à force d'optimiser vous allez passer dans les temps négatifs

  11. #11
    Membre habitué
    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
    Points : 199
    Points
    199
    Par défaut
    Bon effectivement je m'etais juste trompé d'appel de procédure j'avais nommé ma procedure DeleteEmptyWord3 et j'appelais toujours la DeleteEmptyWord2 j'ai honte.

    Sinon, je tombe à 4 secondes au lieu de 7s mais le problème c'est qu'apres je me retrouve avec des chaines vides qui me génent pour la suite de mon traitement.

    Comment puis-je modifier
    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
    function  RetablirOrdreInitial(const ListeSourceInd : TStringList) : TStringList;
    //        Pour ListeSourceInd qui contient dans ses Objects les indices-de-l'ordre-initial
    //        Renvoie une liste rétablie dans l'ordre initial
    var       i,indMemorise : integer;
    begin     Result:=TStringList.create;
              for i:=0 to ListeSourceInd.count-1 do
              begin // initialisation nouvelle liste et en même temps on met rien en object
                    // pour virer les objects en virant après l'appel la liste-source
                    Result.Add('');
              end;
              for i:=0 to ListeSourceInd.count-1 do
              begin // on place dans les chaines '' le mot correspondant à l'indice-initial
                    // mémorisé dans l'object
                    indMemorise:=integer(ListeSourceInd.Objects[i]);
                    Result[indMemorise]:=Trim(ListeSourceInd[i]);
              end;
    end;
    Pour avoir les chaînes vides en moins ??

    j'ai ajouté à la suite de l'appel à cette function :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ...
            StringListMotsDuTexteAAusculter:=RetablirOrdreInitial(lObject);
     
            i:=StringListMotsDuTexteAAusculter.Count-1;
            While i>=0 do
            Begin
              if StringListMotsDuTexteAAusculter[i]='' then
                StringListMotsDuTexteAAusculter.Delete(i);
              Dec(i);
            End;
    ...
    Et biensur je dépasse les 7 secondes facilement.

    Merci pour votre aide.

  12. #12
    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
    Points : 3 263
    Points
    3 263
    Par défaut
    Salut Bruno,

    1 ) Tu dis "Sinon, je tombe à 4 secondes au lieu de 7s" : Je m'attendais à mieux. D'où deux vérifs à faire :
    - Est-ce-que Sorted est bien à true avant de faire appel à IndexOfSL3 ?
    - Est-ce-que la version d'IndexOfSL3 appelée par DeleteEmptyWord est bien la version complète et non la version simplifiée qui portait le même nom ?

    2 ) Tu dis ensuite "mais le problème c'est qu'apres je me retrouve avec des chaines vides qui me génent pour la suite de mon traitement"

    2.1) Avant d'aborder le problème des chaînes vides je voudrais déjà souligner l'intérêt du recours au remplacement des mots-vides par des chaînes vides ce qui permet à plusieurs reprises d'éviter les
    Delete(i) qui sont gourmands en temps d'exécution vu qu'à chaque Delete(i) Delphi est obligé en arrière-plan de décaler toutes les cases de la Stringlist situées de "i" jusqu'à count-1 vers l'avant. Et ce temps d'exécution est gagné :
    - D'abord dans la boucle de DeleteEmptyWord,
    - Et ensuite pour rétabllir l'ordre initial le recours aux chaînes vides a permis soigneusement d'éviter d'avoir à rétablir cet ordre par des permutations de lignes avec des séquences du style Delete(i) + Insert(j,maChaine) qui sont tous les deux gourmands en temps.

    2.2) Problème des chaines vides : Il y a deux pistes à envisager :
    - conserver les chaînes vides et examiner la "gêne" pour voir si la meilleure solution ne se trouverait pas de ce côté.
    - et s'il faut vraiment supprimer dans une StringList des lignes dont la chaîne est vide dans ce cas vaut mieux le faire autrement qu'avec des Delete(i) c'est à dire en créant une nouvelle liste LSSansChainesVides (avec sorted=false) à partir de StringListMotsDuTexteAAusculter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    function  ListeSansChainesVides(const ListeAvecChainesVides : TStringList) : TStringList;
    var       i : integer;
    begin     Result:=TStringList.create;
                Result.Sorted:=false;
              for i:=0 to ListeAvecChainesVides.count-1
               do if ListeAvecChainesVides[i]<>''
                  then Result.Add(ListeAvecChainesVides[i]);
    end;
    A titre indicatif la création avec cette fonction d'une nouvelle liste sans chaines vides à partir d'une autre qui contient 2000 lignes d'un mot a mis chez moi 0,75 ms (Pentium III 1,13 GHz).
    Si j'ai un moment je ferai un test comparatif avec 2000 Delete(i)
    A+

    EDIT même jour 13h55 : tests avec la même liste de 2000 lignes :
    - pour 2000 Delete(0) : mis 8,57 ms (donc avec 2000 fois un décalage du reste de la liste)
    - pour 2000 Delete(count-1) : mis 0,49 ms (donc des Del sans aucun décalage)
    ... si je connaissais le pourcentage que représente le nombre de chaines vides présentes dans tes listes je pourrais faire un test un peu plus réaliste.
    ... en attendant on peut toutefois observer que le temps mis pour vider complètement cette liste avec des Delete(0) permet de créer 8,57/0,75 = 11,4 nouvelles listes sans chaines vides.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  13. #13
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Je n'ai pas tout lu, mais pourquoi traiter ce problème après le LoadFromFile

    il suffit de surcharger la TStringList, de modifier le Add (qui sera appelé par le ":= Text") ... et donc cela économise des insert, cela évite des delete ... n'est ce pas plus intelligent ... quand j'ai fait le dictionnaire du fichier NX pour un de mes employeurs, avant d'insérer le mot en base de données, je vérifiais si ce mot n'était pas un mot interdit (IsBlackWord) ... pour une liste on peut faire pareil et travailler en Amont ...

    on aurait un truc du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
     
       TRestrictedEvent = procedure(const S: string; out DoInsert: Boolean) of object;
     
       TStringListRestricted = class(TStringList)
       private
     
          FOnRestricted: TRestrictedEvent;
       public
          function AddObject(const S: string; AObject: TObject): Integer; override;
          property OnRestricted: TRestrictedEvent read FOnRestricted write FOnRestricted;
       end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function TStringListRestricted.AddObject(const S: string; AObject: TObject): Integer;
    var
       DoInsert: Boolean;
    begin
       Result := -1;
       DoInsert := False;
       FOnRestricted(S, DoInsert);
       if DoInsert then begin
          inherited AddObject(S, AObject);
       end;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TFrmTestMemory.BtnFillListRestrictedClick(Sender: TObject);
    var
       RestrictedList: TStringListRestricted;
    begin
       RestrictedList := TStringListRestricted.Create();
       try
          RestrictedList.OnRestricted := EventRestricted;
          RestrictedList.LoadFromFile(ExtractFilePath(Application.ExeName) + 'Files\' + ExtractFileName(ChangeFileExt(Application.ExeName, '.txt')));
          // ...
       finally
          RestrictedList.Free();
       end;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TFrmTestMemory.EventRestricted(const S: string; out DoInsert: Boolean);
    begin
       DoInsert := (ListeAvecChainesVides.IndexOf(S) < 0);
    end;
    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

  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
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    ShaiLeTroll a écrit :
    Je n'ai pas tout lu, mais pourquoi traiter ce problème après le LoadFromFile
    ... c'est que Bruno charge d'abord les textes,
    ensuite il en identifie la langue (anglais, français, etc),
    ensuite il convertit les textes des langues qui usent de caractères accentués pour leur retirer les accents, il retire également les caractères de ponctuation,
    et ensuite il supprime les "mots-vides" (ex : a, about, above, after, again, against, all ... dessus, dessous, ...) et comme il supprimait non seulement ces mots mais carrément la ligne-conteneur de ce mot avec des Delete(i) l'objectif était d'éviter le ralentissement dû aux Delete(i) répétitifs par une autre parade ... d'où l'idée de remplacer simplement les mots-vides par des chaines-vides.

    Par contre rien n'interdit de charger le contenu de la StringListSansAccents dans une StringListRestricted lors d'un appel à la function AddObject() override; ... c'est effectivement plus judicieux de fermer la porte aux mot-vides lors de l'AddObject que de les laisser rentrer pour être enquiquiné ensuite pour les supprimer. pour ton idée.
    En plus on pourrait profiter de cette même étape pour placer l'indice de l'ordre-initial des mots-du-texte dans l'Object associé au mot de façon à pouvoir au fil des étapes suivantes travailler au besoin avec Sorted=true ou false selon les circonstances pour être toujours dans les meilleures conditions de vitesse tout en pouvant rétablir rapidement l'ordre-initial en fonction des besoins.
    Jusqu'à présent il est descendu d'abord de 2 min à 7s et ensuite de 7s à 4s mais avec uneStringListRestricted.AddObject() il devrait descendre en dessous d'Epsilon vu que la création ligne par ligne d'une liste à partir du contenu d'une autre liste c'est Epsilon comme vu précédemment.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Citation Envoyé par Gilbert Geyer
    Bonjour,

    Citation Envoyé par ShaiLeTroll
    Je n'ai pas tout lu, mais pourquoi traiter ce problème après le LoadFromFile
    ... c'est que Bruno charge d'abord les textes,
    ensuite il en identifie la langue (anglais, français, etc),
    Oups, je me suis mal exprimé, je voulais dire :

    mais pourquoi traiter ce problème après le éStringList.Text:=Texte" ... j'ai confondu avec son LoadFromFile de sa BlackWordList ...

    Sinon, lorsque l'on copie une liste dans une autre, l'affectation du Capacity optimise l'allocation mémoire
    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

  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
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    ShaiLeTroll a écrit :
    Oups, je me suis mal exprimé, je voulais dire :
    mais pourquoi traiter ce problème après le StringList.Text:=Texte" ...
    ... c'est pas grave, l'essentiel c'est de pouvoir utiliser tes TStringListRestricted et ça marche bien je viens de faire l'essai suivant après une légère modif utile à mon essai :
    - J'ai créé une TStingList à partir d'une liste de 2000 mots en y ajoutant une ligne vide un coup sur deux soit une liste de 4000 lignes en tout
    - Ensuite j'ai chonométré le temps mis pour la création d'une TStringListRestricted à partir de la liste précédente : mis 0,48 ms
    Pour faire cet essai j'ai été obligé de modifier la procedure TForm1.EventRestricted( const S: string; out DoInsert: Boolean) pour l'adapter au cas des chaines-vides du style '' où DoInsert := Length(S) > 0;

    Par contre Bruno13 aura intérêt à l'adapter à la fois au cas des ListeAvecMotsVides et qui peuvent d'origine comporter également des chaines-vides résultant de séquences #13#10#13#10 provenant de la mise en page des textes d'origine ce qui conduit à un DoInsert déterminé en fonction de Length(S) et en fonction de l'absence/présence d'un des mots-vides dans la ListeAvecMotsVides.

    ShaiLeTroll a écrit :
    Sinon, lorsque l'on copie une liste dans une autre, l'affectation du Capacity optimise l'allocation mémoire
    ... je suppose qu'il suffit d'écrire avant la copie maListeCopie.capacity := maListeSource.capacity.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  17. #17
    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
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Comme l'idée géniale de ShaiLeTroll consiste, au lieu d'enlever le mots vides d'une liste, à les empêcher d'y rentrer, et que j'ai pu faire plus simple que son code voici une fonction qui réalise cet objectif avec des TStringList standards :
    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
     
    function  CreerListeSansMotNiChaineVide(const ListeOrdreIni,ListeMotsVides : TStringList) : TStringList;
    //        ListeOrdreIni peut contenir tout (doublons, chaînes-vides, mots-vides) sauf des caractères accentués ou de ponctuation, avec un seul mot par ligne
    //        ListeMotsVides doit être triée avant l'appel, dépourvue de caractère accentués ou de ponctuation, avec un seul mot par ligne entièrement en majuscules ou en minuscules
    //        Avant l'appel, ListeMotsVides doit non seulement être triée mais sa
    //        propriété Sorted doit être mise à true car la méthode Sort ne bascule pas cette propriété à true.
    var       i : integer; Mot : string;
    begin     Result:=TStringList.create;
              with Result do
              begin Sorted:=false;   //< le résultat est restitué dans l'ordre initial
                    Capacity:=ListeOrdreIni.capacity;
                    for i:=0 to ListeOrdreIni.count-1 do
                    begin Mot:=ListeOrdreIni[i];
                          // Si Mot<>'' et si Mot ne figure pas dans la liste des mots-vides on le laisse rentrer dans la liste Resultat
                          if (Mot<>'') and (IndexOfSL3(ListeMotsVides,Mot)<0)
                          then AddObject(Mot,tObject(integer(Result.count-1)));
                    end;
              end;
    end;
    ... comme dans cette fonction on n'utilise ni Delete() ni Insert() on évite tous les désagréments dûs à la lenteur de ces deux là.
    ... et comme IndexOfSL3 est plus rapide lorsque ListeMotsVides est triée et que sa propriété Sorted est à true on a donc réuni les conditions optimales de vitesse à ce niveau là.

    ListeDesMots du texte : trier ou pas trier :
    - Pour l'instant j'ai nommé dans cette fonction par ListeOrdreIni ta StringListMotsDuTexteAAusculter en ce sens que j'hésite finalement sur l'intérêt qu'il y aurait à trier cette liste pour les raisons suivantes :
    - IndexOfSL3 cherche dans ListeMotsVides et non dans ListeOrdreIni,
    - ListeMotsVides est généralement nettement plus courte que ListeOrdreIni, ce qui est aussi favorable pour IndexOfSL3,
    - le tri de ListeOrdreIni avec Sort prendrait, on l'a vu, 28 fois plus de temps que la création d'une liste de même longueur avec de simples Add,
    - et en plus, que ListeOrdreIni soit triée ou pas triée de toutes façons ce sont tous les mots inclus dans ListeOrdreIni qu'il faut passer en revue.
    En conséquence de ceci je suggère de démarrer avec des ListeOrdreIni-non-triées pour tester la fonction CreerListeSansMotNiChaineVide() et en apprécier la rapidité avec tes listes et rien n'empêchera de faire ensuite un essai avec des listes-triées (il est préférable de procéder par étapes pour ce point vu qu'avec l'idée de ShaiLeTroll on a changé de stratégie).

    A Bruno13 : J'ai comparé qualitativement les résultats de cette fonction avec la même où au lieu d'utiliser IndexOfSL3 c'est IndexOf-version-standard qui était active et comme je ne trouvais pas des résultats identiques j'ai trouvé qu'une partie de l'écart provenait de la présence de mots avec des caractères accentués présents dans mes listes d'essais mais l'autre partie de l'écart provenait d'un bug dans la version d'IndexOfSL3 qui est en ta possession donc voici la version rectifiée en conséquence :
    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
    32
    33
    34
    35
    36
     
    function IndexOfSL3(SL : TStringList; const S: string): Integer;
    // Si SL.Sorted=False la présence de caractères accentués ne fausse pas le résultat.
    // Si SL.Sorted=True n'utiliser cette fonction que pour des chaînes non accentuées entièrement en majuscules ou en minuscules;
    // sinon remplacer le calcul de C par C := CompareStr() qui est plus lent
    var      L, H, I, C: Integer; ok : boolean;
    begin    with SL do
             begin Result := -1;
                   // Cas SL non triée : Parcours depuis début de liste vers fin :
                   if Not Sorted then
                   begin I:=-1;
                         repeat inc(I);
                         until  (SL[I] = S) or (I = Count-1);
                         if SL[I] = S then Result:= I;
                         EXIT;
                   end;
                   // Cas SL triée : Parcours depuis la médiane de la liste
                   // vers le début ou la fin en fonction du signe de C :
                   L := 0;
                   H := Count - 1;
                   ok:=false;
                   while L <= H do
                   begin I := (L + H) shr 1;
                         if SL[i] < S then C:=-1 else
                         if SL[i] > S then C:=+1 else C:=0;
                         if C < 0 then L := I + 1 else
                         begin H := I - 1;
                               if (C = 0) then
                               begin ok:=true;
                                     if Duplicates <> dupAccept then L := I;
                               end;
                         end;
                   end;
                   if ok then Result:= L;
             end; 
    end;
    A titre indicatif le temps mis par la fonction CreerListeSansMotNiChaineVide() à partir d'une liste de 4000 mots dont un mot sur 2 est une chaîne-vide et compte tenu d'une ListeDeMotsVides de 300 mots extraits parmi les chaines-non-vides de la précédente a été de 4 à 5 ms (Pentium III à 1,13 GHz)
    A+

    EDIT du 23/07 13h23 :
    Dans la function CreerListeSansMotNiChaineVide() il vaut mieux remplacer
    Mot:=ListeOrdreIni[i] par Mot:=Trim(ListeOrdreIni[i]) de façon à éliminer également les chaines presque vides formées de plusieurs caractères-espace.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  18. #18
    Membre habitué
    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
    Points : 199
    Points
    199
    Par défaut
    Comment dire IMPRESSIONNANT !!!

    ce n'est plus une voiture de course que j'ai maintenant mais carrement une fusée !!

    J'ai juste ajouté dans la fonction un test supplémentaire pour supprimer les termes commencant par des chiffres et autres caractères non-alphabetiques:

    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
    function  CreerListeSansMotNiChaineVide(const ListeOrdreIni,ListeMotsVides : TStringList) : TStringList;
    //        ListeOrdreIni peut contenir tout (doublons, chaînes-vides, mots-vides) sauf des caractères accentués ou de ponctuation, avec un seul mot par ligne
    //        ListeMotsVides doit être triée avant l'appel, dépourvue de caractère accentués ou de ponctuation, avec un seul mot par ligne
    //        Avant l'appel, ListeMotsVides doit non seulement être triée mais sa
    //        propriété Sorted doit être mise à true car la méthode Sort ne bascule pas cette propriété à true.
    var       i : integer; Mot : string;
    begin     Result:=TStringList.create;
              with Result do
              begin Sorted:=false;   //< le résultat est restitué dans l'ordre initial
                    Capacity:=ListeOrdreIni.capacity;
                    for i:=0 to ListeOrdreIni.count-1 do
                    begin Mot:=ListeOrdreIni[i];
                          // Si Mot<>'' et si Mot ne figure pas dans la liste des mots-vides on le laisse rentrer dans la liste Resultat
                          if (Mot<>'') and
                             (Mot[1] in ['a'..'z', 'A'..'Z']) and
                             (IndexOfSL3(ListeMotsVides,Mot)<0)
                          then AddObject(Mot,tObject(integer(Result.count-1)));
                    end;
              end;
    end;
    Merci à toi Gilbert et biensûr ShaiLeTroll pour vos idées.

    Prochaine étape : l'affichage des mots, co-occurrence des mots dans un virtual TreeView tout en calculant la Frequence et l'Occurrence.

    Amicalement,
    Bruno

  19. #19
    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
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Bruno13 a écrit :
    ce n'est plus une voiture de course que j'ai maintenant mais carrément une fusée !!
    ... bigre, bonne nouvelle, ça confirme que l'idée de ShaiLeTroll est géniale,
    ... mais tu nous laisses un peu sur notre soif,
    ... on savait que t'étais descendu de 2 min à 7 sec grâce aux suggestions de Pierre Castelain,
    ... et avec la fusée t'es descendu de 7 sec à combien ?
    A propos de virtual TreeView : tu dis "tout en calculant la Frequence et l'Occurrence" :Tu fais quelle distinction dans ton code entre "Fréquence et Occurrence" vu que dans le langage courant c'est à peu près kif-kif ?

    A+

    EDIT : j'allais oublier, il y a aussi l'idée de Graffito qui était déjà prise en compte par IndexOfSL3 suite à l'autre discussion sur l'optimisation d'IndexOf.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  20. #20
    Membre éprouvé
    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
    Points : 988
    Points
    988
    Par défaut
    Non, "Occurences" a plutôt à voir avec "Effectif".

    Mais : Fréquence = Effectif / Effectif total

    On peut multiplier par 100 pour obtenir des pourcentages.

    Exe : sur une liste de 20 mots, j'ai 8 fois le mot "le", le nombre d'occurences de "le", ou effectif, est de 8, l'effectif total est 20, et la fréquence est donc de 8/20 = 0,4 ; ou 40% si on préfère.

    Ce qui m'énerve, c'est le nombre de gens qui ne savent plus ce qu'est une fréquence, alors qu'ils ont étudié ça au collège...

Discussions similaires

  1. Y-a-t-il plus rapide pour enlever les accents ?
    Par Bruno13 dans le forum Langage
    Réponses: 48
    Dernier message: 12/05/2023, 11h24
  2. [Bash] et [Perl] - le plus rapide pour parcourir un fichier ?
    Par Bahan_auboulot dans le forum Langages de programmation
    Réponses: 3
    Dernier message: 23/12/2008, 10h46
  3. [XHTML] Moyen plus rapide pour mettre mes pages en XHTML
    Par Linoa dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 30/08/2005, 17h46
  4. Algo le plus rapide pour trouver une répétition ?
    Par AsmCode dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 28/07/2005, 00h26
  5. Réponses: 16
    Dernier message: 19/05/2005, 16h20

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