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

Langage Delphi Discussion :

TList<T> filtrer selon des critères


Sujet :

Langage Delphi

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    174
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 174
    Points : 38
    Points
    38
    Par défaut TList<T> filtrer selon des critères
    Bonjour,

    J'utilise une list générique de la forme suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     TDonnee = record
       Element : String;
       Famille : String;
       Masse : Double;
       TauxFusion : Double;
     end;
     
     TImportExportInventaire = class
     private
      FListeDonnees : TList<TDonneeImport>;
     
    end;
    Je voudrais pouvoir filtrer cette liste FListeDonnees selon au moins 2 critères :
    - soit lister tous les items de la liste dont la propriété Element est 'toto'
    - soit lister tous les items de la liste dont la propriété Famille est 'toto'
    - voire éventuellement lister tous les items dont la propriété Masse est supérieure à une certaine valeur

    Quelle serait la méthode la plus élégante pour faire ça?
    J'ai cru comprendre qu'on pouvait le faire en utilisant des énumérateurs. Je suis preneur d'un exemple concret.

    Merci d'avance.

  2. #2
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 564
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 564
    Points : 3 968
    Points
    3 968
    Par défaut
    Salut

    En cherchant rapidement sur le Net, il semble que la notion de filtre n'existe pas directement dans TList, il va falloir trouver une technique de remplacement.
    Si tu cherches à parcourir ta liste en ignorant certains articles, un itérateur est une solution adaptée mais je pense qu'il ne te rendra aucun service pour l'accès direct (via l'index de liste) ou la recherche.

    Cela fait longtemps que je n'ai pas travaillé avec Delphi et je connais surtout D7 dans lequel il n'est pas possible de définir un itérateur comme conçu actuellement.

    Avec version de Delphi travailles-tu ?

    Cdlt

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 710
    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 710
    Points : 25 593
    Points
    25 593
    Par défaut
    Je n'ai pas eu besoin de faire, plutôt des Tris avec TArray.Sort
    La TList<> contient une méthode Sort mais par le TObjectDictionary ( c'est le type de SessionDestinationList )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        // Calcul du plan selon la quantité
        OrderedDestinations := SessionDestinationList.ToArray();
        DestinationListOrderer := TDestinationListOrderer.Create();
        try
          TArray.Sort<TDestinationListIterator>(OrderedDestinations, DestinationListOrderer);
        finally
          DestinationListOrderer.Free();
        end;
    Tu pourrais t'inspirer de cela pour créer une Template d'algo

    il te faudrait déclarer une interface inspiré de IComparer nommé IFilter

    Voici un code approximatif mais cela peut te donner une idée avoir un code qui semble élégant !

    un code générique qui pourra servir de modèle pour faire un filter (plutôt une extraction qu'un filtre d'ailleurs)
    Utile si tu as très souvent ce type d'algo à effectuer
    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
     
     
      IFilter<T> = interface
        function Filter(const Item: T): Boolean;
      end;
     
      TFilter<T> = class(TInterfacedObject, IFilter<T>)
      public
        function Filter(const Item: T): Boolean; virtual; abstract;
      end;
     
      TListFilter = class
      public
        class function Filter<T>(const Filter: IFilter<T>): TArray<T>;
      end;
     
    class procedure TListFilter.Filter<T>(List: TList<T>; const Filter: IFilter<T>): TArray<T>;
    var
      item: T;
      I: Integer;
    begin
      for item in List do
      begin
        if Filter.Filter(List) then
        begin
          I := Length(Result);
          SetLength(Result, I+1);
          Result[I] := Item;
        end;
      end;
    end;
    la partie implémentation spécifique à ton projet

    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
     
      TFilterImplementation = TFilter<TDonnee>
      private
        FFilterValueFamille: string;
        FFilterValueElement: string;
      public
        function Filter(const Item: TDonnee): Boolean; override;
        property FilterValueFamille: string read FFilterValueFamille write FFilterValueFamille;
        property FilterValueElement: string read FFilterValueElement write FFilterValueElement;
      end;
     
     
    function TFilterImplementation.Filter(const Item: TDonnee): Boolean; 
    begin
      Result := SameText(Item.Element, FilterValueElement) and SameText(Item.Famille, FilterValueFamille);
    end;
     
    var
      FilteredArray: TArray<T>;
    ...
     
        FilterImplementation := TFilterImplementation.Create();
        try   
          FilterImplementation.FilterValueElement := 'toto';
          FilterImplementation.FilterValueFamille := 'titi';
          FilteredArray := TListFilter.Filter<TDonnee>(List, FilterImplementation);
        finally
          FilterImplementation.Free();
        end;
     
      FilteredArray ... contient une copie filtrée de List<TDonnee>
    Ce n'est pas forcément ce que tu cherches mais ça donne des idées

    Sinon faudrait créer une TFilteredList qui soit capable de fournir un itérateur de filtré,
    cela implique de surcharger DoGetEnumerator
    Faudrait faire une iterace IFilterableIterator qui sera une redéfinition de Iterator avec une factory fournissant un IFilter
    En plus du code de IFilter et TListFilter, il y aurait cela en plus à coder

    C'est un sujet intéressant, si j'ai le temps, je tenterais de fabriquer une TFilteredList complètement générique


    Personnellement, je ne suis jamais allez aussi loin

    Lorsque j'ai un traitement sur une liste et que je cherche plusieurs éléments de même nature, je fais une simple boucle (même sur une TList<>)
    Je n'utilise l'énumérateur que sur un TDictionnary si je suis obligé de le parcourir, ce qui est rarement le cas
    FOriginInfos et FIdentificationClients sont TDictionnary<>
    FKeepAlives est TList<>

    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
    ------------------------------------------------------------------------------
    procedure TAutomateLogistiqueModuleNotificationReceiver.RemoveOrigin(AOrigin: TThomModuleAutomateLogistique.TRemoteMessageSocketHandle);
    var
      I: Integer;
      KeepAliveInfo: TKeepAliveInfo;
    begin
      // TDictionary.Remove : Aucune exception n'est déclenchée si la clé n'est pas présente dans le dictionnaire
     
      // Nettoyage des informations de connexion par origine
      FOriginInfosLock.BeginWrite();
      try
        FOriginInfos.Remove(AOrigin);
      finally
        FOriginInfosLock.EndWrite();
      end;
     
      // Nettoyage des informations d'identification par origine
      FIdentificationClientsLock.BeginWrite();
      try
        FIdentificationClients.Remove(AOrigin);
      finally
        FIdentificationClientsLock.EndWrite();
      end;
     
      // Inutile de conserver les dates de KeepAlive pour une connexion terminée
      FKeepAlivesLock.BeginWrite();
      try
        for I := FKeepAlives.Count - 1 downto 0 do
        begin
          KeepAliveInfo := FKeepAlives.Items[I];
          if KeepAliveInfo.Origin = AOrigin then     // C'est ici le filter !
            FKeepAlives.Delete(I);
        end;
      finally
        FKeepAlivesLock.EndWrite();
      end;
    end;

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 710
    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 710
    Points : 25 593
    Points
    25 593
    Par défaut
    J'ai eu le temps en fin de journée de faire cette TFilteredList !
    Et maintenant, c'est le week end !


    double emploi :
    Utilisation de TFilteredList comme une TList<>
    Utilisation de TFilteredList.ExtractByFilter ponctuellement sur une TList<>


    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
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    //------------------------------------------------------------------------------
    (*                SoLuTions is an Versatile Library for Delphi                 -
     *                                                                             -
     *  Version alternative publiée sur "www.developpez.net"                       -
     *  Post : "TList<T> filtrer selon des critères"                               -
     *  Post Number : 8377244                                                      -
     *  Post URL = "http://www.developpez.net/forums/d1541925/environnements-developpement/delphi/langage/tlist-t-filtrer-selon-criteres/#post8377244"
     *                                                                             -
     *  Copyright "SLT Solutions", (2015)                                          -
     *                                                                             -
     * Ce logiciel est un programme informatique servant à aider les développeurs  -
     * Delphi avec une bibliothèque polyvalente, adaptable et fragmentable.        -
     *                                                                             -
     * Ce logiciel est régi par la licence CeCILL-C soumise au droit français et   -
     * respectant les principes de diffusion des logiciels libres. Vous pouvez     -
     * utiliser, modifier et/ou redistribuer ce programme sous les conditions      -
     * de la licence CeCILL-C telle que diffusée par le CEA, le CNRS et l'INRIA    -
     * sur le site "http://www.cecill.info".                                       -
     *                                                                             -
     * En contrepartie de l'accessibilité au code source et des droits de copie,   -
     * de modification et de redistribution accordés par cette licence, il n'est   -
     * offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,   -
     * seule une responsabilité restreinte pèse sur l'auteur du programme,  le     -
     * titulaire des droits patrimoniaux et les concédants successifs.             -
     *                                                                             -
     * A cet égard  l'attention de l'utilisateur est attirée sur les risques       -
     * associés au chargement,  à l'utilisation,  à la modification et/ou au       -
     * développement et à la reproduction du logiciel par l'utilisateur étant      -
     * donné sa spécificité de logiciel libre, qui peut le rendre complexe à       -
     * manipuler et qui le réserve donc à des développeurs et des professionnels   -
     * avertis possédant  des  connaissances  informatiques approfondies.  Les     -
     * utilisateurs sont donc invités à charger  et  tester  l'adéquation  du      -
     * logiciel à leurs besoins dans des conditions permettant d'assurer la        -
     * sécurité de leurs systèmes et ou de leurs données et, plus généralement,    -
     * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.          -
     *                                                                             -
     * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez      -
     * pris connaissance de la licence CeCILL-C, et que vous en avez accepté les   -
     * termes.                                                                     -
     *                                                                             -
     *----------------------------------------------------------------------------*)
    unit SLT.Common.Generics.FilteredList;
     
    interface
     
    uses System.Generics.Collections;
     
    type
      IFilter<T> = interface
        function Filter(const Item: T): Boolean;
      end;
     
      TFilter<T> = class;
     
      TFilteredList<T> = class(TList<T>)
      private
        FFilter: TFilter<T>;
      protected
        function DoGetEnumerator(): TEnumerator<T>; override;
      public
        class function ExtractByFilter(AList: TList<T>; const AFilter: IFilter<T>): TArray<T>;
     
        property Filter: TFilter<T> read FFilter write FFilter;
     
        type
          TFilteredEnumerator = class(TList<T>.TEnumerator)
          private
            FFilteredList: TFilteredList<T>;
          protected
            function DoMoveNext(): Boolean; override;
          public
            constructor Create(AFilteredList: TFilteredList<T>);
            function MoveNext(): Boolean;
          end;
     
        function GetEnumerator(): TFilteredEnumerator; reintroduce;
      end;
     
      TFilterEvent<T> = reference to function(const Item: T): Boolean; // Méthode anonyme qui acceptent soit un gestionnaire d'évènement déclaré soit directement un bloc fonction
     
      TFilter<T> = class(TInterfacedObject, IFilter<T>)
      private
        FOnFilter: TFilterEvent<T>;
      protected
        function DoFilter(const Item: T): Boolean; virtual;
      public
        function Filter(const Item: T): Boolean;
     
        property OnFilter: TFilterEvent<T> read FOnFilter write FOnFilter;
      end;
     
     
     
     
    implementation
     
    { TFilteredList<T> }
     
    //------------------------------------------------------------------------------
    function TFilteredList<T>.DoGetEnumerator: TEnumerator<T>;
    begin
      Result := GetEnumerator();
    end;
     
    //------------------------------------------------------------------------------
    class function TFilteredList<T>.ExtractByFilter(AList: TList<T>; const AFilter: IFilter<T>): TArray<T>;
    var
      item: T;
      I: Integer;
    begin
      for item in AList do
      begin
        if AFilter.Filter(item) then
        begin
          I := Length(Result);
          SetLength(Result, I+1);
          Result[I] := Item;
        end;
      end;
    end;
     
    //------------------------------------------------------------------------------
    function TFilteredList<T>.GetEnumerator(): TFilteredEnumerator;
    begin
      Result := TFilteredEnumerator.Create(Self);
    end;
     
    { TFilteredList<T>.TFilteredEnumerator }
     
    //------------------------------------------------------------------------------
    constructor TFilteredList<T>.TFilteredEnumerator.Create(AFilteredList: TFilteredList<T>);
    begin
      inherited Create(AFilteredList);
      FFilteredList := AFilteredList;
    end;
     
    //------------------------------------------------------------------------------
    function TFilteredList<T>.TFilteredEnumerator.DoMoveNext(): Boolean;
    begin
      while inherited DoMoveNext() do
        if FFilteredList.Filter.Filter(Current) then
          Exit(True);
    end;
     
    //------------------------------------------------------------------------------
    function TFilteredList<T>.TFilteredEnumerator.MoveNext(): Boolean;
    begin
      Result := DoMoveNext();
    end;
     
    { TFilter<T> }
     
    //------------------------------------------------------------------------------
    function TFilter<T>.DoFilter(const Item: T): Boolean;
    begin
      if Assigned(FOnFilter) then
        Result := FOnFilter(Item)
      else
        Result := True;
    end;
     
    //------------------------------------------------------------------------------
    function TFilter<T>.Filter(const Item: T): Boolean;
    begin
      Result := DoFilter(Item);
    end;
     
    end.
    le code de test, j'ai mis ça dans une application de divers, j'ai manipulé du TColor

    Je te laisse écrire un code de test sur TDonne, si tu as besoin d'aide, je pourrais aider

    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
     
    procedure TZooThomVCLMainForm.rgrpFiltreCouleurClick(Sender: TObject);
     
      procedure FillColorList(AList: TList<TColor>);
      var
        I: Integer;
      begin
        for I := 0 to lvColors.Items.Count - 1 do
          AList.Add(lvColors.Items[I].GroupID);
      end;
     
      procedure ExtractArrayColors(AList: TList<TColor>);
      var
        A: TArray<TColor>;
        F: TFilter<TColor>;
        I: Integer;
      begin
        F := TFilter<TColor>.Create();
        try
          F.OnFilter := function(const Item: TColor): Boolean // va savoir pourquoi mais pas de ; en fin de déclaration d'une méthode anonyme
                        var
                          RGBColor: TSLTColorRGB;
                        begin
                          RGBColor.Color := Item;
                          case rgrpFiltreCouleur.ItemIndex of
                            1: Result := ByteBool(RGBColor.Red);
                            2: Result := ByteBool(RGBColor.Green);
                            3: Result := ByteBool(RGBColor.Blue);
                          else
                            Result := True;
                          end;
     
                          if rgrpFiltreCouleurMode.ItemIndex = 1 then
                            Result := not Result;
                        end;
     
          A := TFilteredList<TColor>.ExtractByFilter(AList, F);
          for I := Low(A) to High(A) do
          begin
            with lvFilteredColors.Items.Add() do
            begin
              Caption := IntToHex(A[I], 8);
              GroupID := A[I];
            end;
          end;
        finally
          F.Free();
        end;
      end;
     
      procedure FilteredIteratorColors(AList: TList<TColor>);
      var
        FL: TFilteredList<TColor>;
        F: TFilter<TColor>;
        it: TColor;
      begin
        FL := TFilteredList<TColor>.Create();
        try
          FL.AddRange(AList.ToArray());
     
          F := TFilter<TColor>.Create();
          try
            F.OnFilter := function(const Item: TColor): Boolean // va savoir pourquoi mais pas de ; en fin de déclaration d'une méthode anonyme
                          var
                            RGBColor: TSLTColorRGB;
                          begin
                            RGBColor.Color := Item;
                            case rgrpFiltreCouleur.ItemIndex of
                              1: Result := ByteBool(RGBColor.Red);
                              2: Result := ByteBool(RGBColor.Green);
                              3: Result := ByteBool(RGBColor.Blue);
                            else
                              Result := True;
                            end;
     
                            if rgrpFiltreCouleurMode.ItemIndex = 1 then
                              Result := not Result;
                          end;
     
            FL.Filter := F;
            for it in FL do
            begin
              with lvFilteredColors.Items.Add() do
              begin
                Caption := IntToHex(it, 8);
                GroupID := it;
              end;
            end;
          finally
            F.Free();
          end;
        finally
          FL.Free();
        end;
      end;
     
    var
      Colors: TList<TColor>;
    begin
      lvFilteredColors.Items.Clear();
     
      Colors := TList<TColor>.Create();
      try
        FillColorList(Colors);
     
        if rgrpFiltreCouleurAlgo.ItemIndex = 0 then
          ExtractArrayColors(Colors)
        else
          FilteredIteratorColors(Colors);
      finally
        Colors.Free();
      end;
    end;

Discussions similaires

  1. [C#] Comment sélectionner un item de listview selon des critères
    Par beufreecasse dans le forum Windows Forms
    Réponses: 1
    Dernier message: 26/10/2006, 21h34
  2. Requetes selon des critères
    Par Z[ee]k dans le forum Access
    Réponses: 6
    Dernier message: 05/06/2006, 15h06
  3. tableau descriptif de SQL server selon des critères techniq
    Par h.sofia dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 16/02/2006, 17h25
  4. Supprimer des sous-dossiers selon des critères
    Par Dertron dans le forum Autres Logiciels
    Réponses: 2
    Dernier message: 18/01/2006, 15h33
  5. lister des fichiers selon des critères
    Par Corben dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 12
    Dernier message: 18/10/2005, 17h52

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