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 :

Comment trier une TStringList suivant le contenu d'un objet associé à cette liste ?


Sujet :

Delphi

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Comment trier une TStringList suivant le contenu d'un objet associé à cette liste ?
    Bonjour, j'ai une liste ListeOffres de type TStringList qui contient par exemple les lignes suivantes :

    camembert 20
    gruyère 10
    etc.........

    à chaque élément de ma liste est associée un objet Prix et un objet titre (respectivement '20' et 'camembert') pour la 1ère ligne.

    J'essaye de trier ma liste en fonction du prix (ordre croissant) => gruyère devrait être avant camembert !

    Voici une partie du code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ListeOffres : TStringList;
     
    (ListeOffres.Objects[i] as ToffresGI).Prix
     
    (ListeOffres.Objects[i] as ToffresGI).titre
    J'ai essayé d'utilisé ((ListeOffres.Objects[i] as ToffresGI).Prix).Sort sans succès.


    Dans un deuxième temps j'essaye de la trier suivant l'ordre alphabétique des titres en utilisant la fonction suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    function TfrmChangeTC.CompareNames(Item1: TComponent ; Item2: TComponent): Integer;
    begin
      Result := CompareText((Item1 as TComponent).Name, (Item2 as TComponent).Name);
    end;
    L'appel de cette fonction ne marche pas non plus.

    Etant débutant en delphi, je ne sais pas si ces options sont les bonnes.
    Si vous avez des pistes, merci d'avance !

  2. #2
    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 266
    Points
    3 266
    Par défaut
    Bonjour,

    à chaque élément de ma liste est associé un objet Prix et un objet titre (respectivement '20' et 'camembert') pour la 1ère ligne.
    ... 2 objets ? bizarre. Pour chaque ligne d'une stringlist on dispose d'une chaîne et d'un seul objet donc si tu mets 'camembert' dans ton objet cela signifie que les cases "chaine" de ta StringList sont vides.

    En fait il est possible de faire un truc du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //A : lors de la création de la liste
          maListeT:=TStringList.create; // maListeT avec T comme Titres d'articles
          maListeT.AddObject('camembert'],tObject(integer(20))); // seuls les prix sont ici mis dans l'objet associé à la case 'chaîne' 
          maListeT.AddObject('gruyère'],tObject(integer(10)));
     
    //B : pour récupérer le prix d'un article d'indice i
           prix:=integer(maListeT.Objects[i]);
     
    //C : ensuite pour trier la liste dans l'odre Alphabétique des titres des articles
           maListeT.Sort;
    D : Reste à régler le problème du tri en fonction des prix :

    Comme la méthode 'Sort' standard ne fonctionne que sur des chaînes de caractères et non sur des valeurs numériques une piste consiste à créer une deuxième StringList maListeP (avec P comme Prix, ...qui peut être temporaire) à partir de la précédente maListeT en plaçant le prix et le nom de l'article dans une chaîne calibrée ou formattée comme suit en mettant le prix devant le nom de l'article et en mettant devant chaque prix un nombre d'espaces tel que les unités sont alignées verticlament entre-elles les dizaines alignées sur les dizaines, etc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
          maListeP.add('   255 whiski-machin);
          maListeP.add('    20 camembert);
          maListeP.Sort; // et la liste est triée en fonction des prix
    Pour calibrer ainsi chaque chaîne supposons que tes prix sont du type Word 0..65535 ce qui fait au max 5 caractères pour les prix :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
         prix:=integer(maListeT.Objects[i]); // récupération du prix dans maListeT 
         strPrix:=intToStr(prix);
         while length(strPrix) < 5 do strPrix:=' '+strPrix; // ajout d''espaces de calibrage au début
         maListeP.add(strPrix+' '+maListeT[i]);
         maListeP.Sort; // et la liste est triée en fonction des prix
    ... et si les prix sont d'un type qui comporte DecimalSeparator il faut que le calibrage des chaînes soit tel que les DecimalSeparator soient alignés varticalement et tous suivis d'un même nombre de caractères numériques pour les décimales pour éviter que la comparaison faite par le tri ne soit faussée par la présence d'un espace à la place d'un zéro dans une colonne de caractères numériques.

    A+

  3. #3
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut

    Pour compléter les propos de Gilbert, je dirais que pour le tri suivant les prix il faut utiliser la procédure CustomSort de la StringList. Elle est spécialement dédiée à ce type de situation.

    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
    37
    38
    39
    40
    41
     
    // Fonction callback de tri
    function TriListe(List: TStringList; Index1, Index2: Integer): Integer;
    var
      v1, v2: Integer;
    begin
      v1 := Integer(List.Objects[Index1]);
      v2 := Integer(List.Objects[Index2]);
      if v1 < v2 then
        result := -1
      else if v1 > v2 then
        result := 1
      else
        result := 0;
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FListeOffres := TStringList.Create;
      FListeOffres.AddObject('Gruyère', Pointer(Integer(10)));
      FListeOffres.AddObject('Camembert', Pointer(Integer(20)));
     
      Memo1.Lines.Assign(FListeOffres);
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      FListeOffres.Free;
    end;
     
    procedure TForm1.BtnTriAlphaClick(Sender: TObject);
    begin
      FListeOffres.Sort;
      Memo1.Lines.Assign(FListeOffres);
    end;
     
    procedure TForm1.BtnTriNumClick(Sender: TObject);
    begin
      FListeOffres.CustomSort(TriListe);
      Memo1.Lines.Assign(FListeOffres);
    end;
    Voilà.
    @+ Claudius

  4. #4
    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 266
    Points
    3 266
    Par défaut
    Re-bonjour,

    Vu le code de Claudius : C'est effectivement plus académique avec CustomSort que mon bidouillage "sytème-D" et en plus on évite ainsi la nécessité de créer une deuxième StringList d'où en plus économie de mem-vive.

    A+

    EDIT : Au fait, dans l'instruction FListeOffres.AddObject('Gruyère', Pointer(Integer(10))); pourrait-on, dans le cadre d'un autre besoin faire FListeOffres.AddObject('Gruyère', Pointer(monRecord))); où monRecord serait du type Record avec un nombre multiple de champs ?

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    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 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Tu peux effectivement mettre un pointeur sur un record, au lieu d'un objet (qui n'est qu'un pointeur aussi), faut juste savoir si qu'il contient pour le transtyper correctement ...

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

    A ShaiLeTroll : Merci pour ta réponse. Faudra que j'essaye un jour en mettant un pointeur sur un record, au lieu d'un objet. Pour l'instant je n'avais utilisé des StringLists qu'avec des BitMap ou des integer en objet. Mais si ça marche aussi avec des record ça donne plein d'idées. En fait je vais peut-être essayer de suite si j'arrive à ne pas rester scotché sur le forum.

    A+

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    petite précision, ma TStringListe ne contient pas les lignes suivantes :

    camembert 20
    gruyère 10
    etc.........

    elles contient en fait un code-barre (10282 par exemple).
    A chaque élément de ma liste (code-barre) est associé un objet prix et un objet titre (respectivement 20 et camembert).

    Du coup j'ai essayé d'utilisé : ListeOffres.CustomSort(TriListe); en ayant déclaré la fonction TriListe.

    Problème à la compilation il me dit que l'identificateur CustomSort n'est pas déclaré, cette fonction doit elle être déclaré ou un simple appel suffit ?

    Par ailleurs en utilisant l'algorithme suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
      v1 := Integer(List.Objects[Index1]);
      v2 := Integer(List.Objects[Index2]);
      if v1 < v2 then
        result := -1
      else if v1 > v2 then
        result := 1
      else
        result := 0;
    Je ne vois pas comment il va parcourir toutes la liste ? et comment il va trier suivant les prix cad suivant mon objet : (ListeOffres.Objects[i] as ToffresGI).Prix

    merci

  8. #8
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut

    Tu peux nous montrer comment tu assignes tes objets aux items de la TStringList.

    Quant à l'erreur de compil sur CustomSort c'est une méthode publique de la classe TStringList, donc inutile de la déclarer.

    @+

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

    Rere29 a écrit: Par ailleurs en utilisant l'algorithme suivant : (... algo de TriListe) Je ne vois pas comment il va parcourir toute la liste ?
    ... en fait ce n'est pas l'algo de la function TriListe qui va parcourir la liste (c'est le nom de cette function qui t'a induit une incompréhension) : TriListe est uniquement la fonction de comparaison qui est passée en paramètre lors du FListeOffres.CustomSort(TriListe); et c'est CustomSort qui va parcourir la la liste et effectuer les comparaisons utiles au tri en utilisant la function TriListe : pour une meilleure lisibilité tu peux renommer TriListe en l'appelant par exemple fComparePrixPourLeTriNumerique.

    Par contre de mon coté j'ai essayé de mettre un pointeur sur un record, au lieu d'un objet pour fair un truc dans le genre maStringList.AddObject('Titre', Pointer(monRecord))); et j'ai tourné en rond sans succès.

    A+

  10. #10
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Re-bonjour,

    J'assigne mes objets aux items de la TStringList de cette façon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ListOffres.Add (value); //ici j'ajoute les codes barres
     
    // je crée mon objet associés à ma liste
    ListOffres.Objects[ListTarifBasculement.Count-1]:=TOffresGI.Create; 
     
    // j'ajoute les prix et les titres (value a des valeurs différentes)
    (ListOffres.Objects[ListOffres.Count-1] as TOffresGI).Prix:=value;
    (ListOffres.Objects[ListOffres.Count-1] as TOffresGI).Titre:=value;
    Ensuite je peut accéder aux prix et aux titres de chaqun des codes-barres en faisant varier l'indice i :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ListeOffres.Objects[i] as ToffresGI).Prix
    (ListeOffres.Objects[i] as ToffresGI).titre
    L'erreur sur le CustomSort vient peut être du fait que lors de l'appel je ne passe pas de paramètre à TriListe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ListOffres.CustomSort(TriListe);
    ?

  11. #11
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Pour mon problème de CustomSort cela ne vient-il pas de ma version de Delphi : Delphi4 ?

  12. #12
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut

    Citation Envoyé par Rere29 Voir le message
    Pour mon problème de CustomSort cela ne vient-il pas de ma version de Delphi : Delphi4 ?
    Je ne crois pas, mais comme je ne suis pas sûr à 100%, essaye avec ce code pour s'en assurer.
    Un TMemo et 3 boutons pour les tris:

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
     
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
     
    type
      TData = class
        Libelle: string;
        Prix: Currency;
      end;
     
      TForm1 = class(TForm)
        Memo1: TMemo;
        BtnTriLib: TButton;
        BtnTriPrix: TButton;
        BtnTriCode: TButton;
     
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure BtnTriLibClick(Sender: TObject);
        procedure BtnTriPrixClick(Sender: TObject);
        procedure BtnTriCodeClick(Sender: TObject);
      private
        { Déclarations privées }
        FListeOffres: TStringList;
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    // Fonction callback de tri sur prix
    function TriListePrix(List: TStringList; Index1, Index2: Integer): Integer;
    var
      v1, v2: Currency;
    begin
      v1 := TData(List.Objects[Index1]).Prix;
      v2 := TData(List.Objects[Index2]).Prix;
      if v1 < v2 then
        result := -1
      else if v1 > v2 then
        result := 1
      else
        result := 0;
    end;
     
    // Fonction callback de tri sur libellé
    function TriListeLib(List: TStringList; Index1, Index2: Integer): Integer;
    var
      v1, v2: string;
    begin
      v1 := TData(List.Objects[Index1]).Libelle;
      v2 := TData(List.Objects[Index2]).Libelle;
      if v1 < v2 then
        result := -1
      else if v1 > v2 then
        result := 1
      else
        result := 0;
    end;
     
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      Data: TData;
    begin
      FListeOffres := TStringList.Create;
     
      Data := TData.Create;
      Data.Libelle := 'Camembert';
      Data.Prix := 20;
      FListeOffres.AddObject('10282 - Camembert - 20', Data);
     
     
      Data := TData.Create;
      Data.Libelle := 'Gruyère';
      Data.Prix := 10;
      FListeOffres.AddObject('12525 - Gruyère - 10', Data);
     
      Data := TData.Create;
      Data.Libelle := 'Bleu';
      Data.Prix := 30;
      FListeOffres.AddObject('11234 - Bleu - 30', Data);
     
      Memo1.Lines.Assign(FListeOffres);
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    var
      I: Integer;
    begin
      with FListeOffres do
      begin
        for I := 0 to Count - 1 do
          if Assigned(Objects[I]) then TData(Objects[I]).Free;
        Free;
      end;
    end;
     
    procedure TForm1.BtnTriLibClick(Sender: TObject);
    begin
      FListeOffres.CustomSort(TriListeLib);
      Memo1.Lines.Assign(FListeOffres);
    end;
     
    procedure TForm1.BtnTriPrixClick(Sender: TObject);
    begin
      FListeOffres.CustomSort(TriListePrix);
      Memo1.Lines.Assign(FListeOffres);
    end;
     
    procedure TForm1.BtnTriCodeClick(Sender: TObject);
    begin
      FListeOffres.Sort;
      Memo1.Lines.Assign(FListeOffres);
    end;
     
    end.
    @+ Claudius

  13. #13
    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 266
    Points
    3 266
    Par défaut
    Binjour,

    En fait avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    type
      TData = class
        Libelle: string;
        Prix: Currency;
        ...
        ...
      end;
    ... on transforme en quelque sorte notre TStringList en une sorte de TObjectList : astucieux.

    A+

  14. #14
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    bonjour,

    bon j'ai fini par réussir à faire ce que je voulais en passant par des tableaux temporaire

    Merci pour vos précieux conseil

    A+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/05/2006, 23h13
  2. [GTK#]Comment afficher une frame et son contenu?
    Par mick2d dans le forum GTK+
    Réponses: 3
    Dernier message: 31/03/2006, 09h35
  3. [C#] Comment trier une DataTable ?
    Par royto dans le forum C#
    Réponses: 2
    Dernier message: 23/03/2006, 01h15
  4. Comment trier une table paradox dans un Ttable sur un Dbgrid
    Par amireve dans le forum Bases de données
    Réponses: 5
    Dernier message: 26/12/2005, 19h28
  5. Comment trier une DBGRID en cliquant sur une colonne
    Par sessime dans le forum Bases de données
    Réponses: 8
    Dernier message: 09/10/2004, 16h18

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