Tri numérique sur ListBox

Résolu
cs_f6dqm1 Messages postés 62 Date d'inscription lundi 8 novembre 2004 Statut Membre Dernière intervention 25 mai 2013 - 19 déc. 2007 à 15:58
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 - 20 déc. 2007 à 19:06
Existe t'il une possibilité de tri numérique automatique sur une ListBox dont tous les items commencent par des chiffres ?
La fonction sorted ne marche pas car elle classe d'abord tous les chiffres qui commencent par 1 puis tous les chiffres qui commencent par 2 etc. Pas réellement ce que je cherche Hi !
Merci pour l'aide
Gabriel

33 réponses

Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
19 déc. 2007 à 16:14
Salut,

pour que le trie fonctionne il faut ajouter des zéros devant les chiffres

001
002
011

 
@+
Cirec

<hr siz="" />
1
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
19 déc. 2007 à 18:56
Tiré de ma fonction, partie oú je traite des doubles/Integers:

Lista étant une TStrings

var i, j, small : Integer;

      for i := 0 to Lista.Count - 2 do       
      begin
          small := i;

          smallVal := StrToFloat(Lista[i]);

          for j := i + 1 to Lista.Count - 1 do 
              if StrToFloat(Lista[j]) < smallVal
              then begin
                small := j;
                smallVal := StrToFloat(Lista[j]);
              end;

        if small <> i                           // Permuter
        then begin
          Str := Lista[i];
          Lista[i] := Lista[small];
          Lista[small] := Str;
        end;

Tu dois juste remplacer StrToFloat() par une fonction qui te renvoie l' integer de l'item!!!
A+
0
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
19 déc. 2007 à 19:04
Une autre façon serait de trier avant de passer les items dans ta liste.
Pour cela, tu peux passer par un Record et un Array:

type
  monRecord=Record
    Valeur: Integer;  // Valeur qui permettra de trouver le plus petit
    MaString; // String qui sera passée dans ta listBox
    Passé: Boolean;  // permet de savoir si on l' a déjá passé dans le listbox
  end;

Tu déclares un aArray comm suit:
Array_Items: Array of monRecord;

Ensuite tu remplies Array_Items avec les différents Items. (N' oublie pas le SetLength de l' array).
"Passé" devra être initialisé à false bien sûr ...

Enfin, tu cherches dans l' array le plus petit (oú Passé = "false") et tu le passes dans ta ListBox.
N' oublie pas de mettre "Passé" à True.

A+
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
19 déc. 2007 à 19:52
@Mauricio:

Ta méthode ne fonctionne que si les Items sont que des chiffres !!!!

Si ses Items contiennent aussi des lettres ... dans ce cas ça plante

Il dit bien "tous les items commencent par des chiffres"
ce qui sous-entend qu'ils contiennent aussi des lettres

Du coup il est plus facile de rajouter des zéros devant

ps : toutes les méthodes de tries réagissent de la même manière ...
donc pour obtenir un résultat correcte il faut ajouter des zéros

 
@+
Cirec

<hr siz="" />
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
19 déc. 2007 à 22:28
Dans ma derniere phrase de mon 1er commentaire j' ai écrit:
"Tu dois juste remplacer StrToFloat() par une fonction qui te renvoie l' integer de l'item!!!"

Mon 2eme commentaire fonctionnerait aussi très bien ...

A+
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
19 déc. 2007 à 22:52
Pourquoi faire simple quand on peut faire compliqué

J'avais bien lu ton message
et j'ai même fait les testes qui s'imposent

StrToInt (par exemple) te renvoie une belle exception si la chaine contient des lettres !

ce qui implique qu'il faudrait créer une fonction qui récupère que les chiffres ... mais le trie ne sera pas juste puisque les lettres ne seront pas prise en compte !!!!

Alors que le simple fait d'ajouter des zéros en début permet d'utiliser la méthode de trie interne et sans code supplémentaire avec un résultat trier correctement jusqu'au dernier caractère

 
@+
Cirec

<hr siz="" />
0
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
19 déc. 2007 à 23:04
çà me fait penser au coup du gars qui veut se faire un diaporama avec ses photos de vacances avec un logiciel tout fait..(photo1, photo2..photo12 etc etc)
et surprise lorsqu'il le lance tout est mélangé !
Alors que si bien sur il se dit tiens j'en ai 999 (il en raté une..) et il nomme ses fichiers :
photo001, photo002, photo047..photo238...photo999.
et là ca va nettement mieux..

cantador
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
20 déc. 2007 à 00:26
Salut,

« Qu'il y ait des gens beaucoup plus savants que d'autres n'est pas très intriguant. Ce qui est extraordinaire, et diablement instructif, c'est à quel point deux personnes ayant des connaissances proches peuvent diverger dans la façon dont elles les interprètent. »

C'est vachement enrichissant les gars !  ;)
0
japee Messages postés 1727 Date d'inscription vendredi 27 décembre 2002 Statut Modérateur Dernière intervention 6 novembre 2021 8
20 déc. 2007 à 09:20
Quelle que soit la manière dont on va traiter le problème, dans tous les cas, il va bien falloir une routine pour récupérer le nombre qui se trouve en début d'item et qui détermine le classement de la liste.
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 déc. 2007 à 09:46
@Caribensila:
Le problème n'est pas là ... peut importe de quel manière on interprète la chose ... ce que je soulignai c'est qu'il n'est pas utile de réécrire ce qui existe déjà !!! (la fonction de trie)

@Japee:
Pas forcément ... on peut le prévoir à l'avance

Soit c'est l'utilisateur qui les rentre dans ce cas on utilise un MaskEdit

Soit c'est le programmeur qui les rentre dans ce cas c'est à lui de les mettre

Il ne reste plus que la machine c'est le seul cas ou il faudrait écrire du code

ça ne fait que 1 cas sur 3 

Et en plus dans méthode de ce type (ou l'on extrait que les chiffres pour le trie) le résultat risque de ne pas être correcte

01 dca
01 cda
01 acd

Penses tu que le résultat sera correcte

Avec la méthode interne on obtiendrait :
01 acd

01 cda

01 dca

sans réécrire la procédure de trie

 
@+
Cirec

<hr siz="" />
0
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
20 déc. 2007 à 10:13
Salut Cirec,
ta méthode est bonne puisque le chiffre est en début de string.
Par contre s' il était à la fin,il y aurait un chtit problème...

C' est pour cela qu' en utilisant un Array de type Record on peut ordonner de la manière que l' on veut, même sans montrer les chiffres dans la listBox.

C' est vrai que c' est plus complexe mais serait 100% réutilisable et cela permet aussi d' ordonner avec d' autres critères que du plus petit au plus grand...

A+
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 déc. 2007 à 10:45
Salut Mauricio:

il faut que je regarde ça de plus près ...
ou j'ai loupé un truc ou j'y ai rien compris.

Mais jusqu'à preuve du contraire une chaine '123 abc'

avec n'importe quel StrTo... provoque une erreur de conversion ... non ?

et c'est là que je ne comprend pas ta logique :
 Puisque même si tu arrives à extraire les chiffres le trie ne se fera que sur les chiffres et non sur l'ensemble des caractères

En attendant que je teste le code je vous offre une fonction qui ajoute les zéros manquants (uniquement devant)

Uses StrUtils;
Function LeadingZero(Const S : String;
Const Len : Integer = 3): String ;
Var PbS : PByte;
    Cnt : Integer;

Begin
  PbS : = PByte(S);

  SetLength(Result, Length(S));
  Result := S;
  Cnt := 0;
   While (PbS^ > 47)
And (PbS^ < 58)
Do Begin
    Inc(PbS);
    Inc(Cnt);

  End;
  If
(Cnt > 0) And
(Cnt < Len) Then Begin

    Cnt : = ABS(Len - Cnt);
    SetLength(Result, Length(S) +
Cnt);
    Result := DupeString('0', Cnt) + S;

  End ;

End;
<center>Highlighted with Pas2HTML

</center>Utilisation :
S : String = '12 String';

LeagingZero(S)       renvoie '012 String'
LeagingZero(S, 5)   renvoie '00012 String'

LeagingZero(S, 2)   renvoie '12 String'

 
@+
Cirec

<hr siz="" />
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 déc. 2007 à 12:32
C'est bien ce que je disais

ton code ne fonctionne que si les données sont uniques ...

{ Voici le contenu de la ListBox
1 zdhr
2 acabd
1 dbdgh
1 abc
11
aabccd
2 aabccd
111 dkfjgu
}
Procedure SortList(Lista : TStrings);
Var i, j, small, smallVal : Integer;
    Str :
String;
    {Function que j'ai ajouté pour récupérer l'integer}
    Function MyStrToInt(S : String): Integer;
    Var

      PbC : PChar;
      TmpStr : String;
    Begin

      PbC := PChar(S);
      TmpStr := '';
       While (PbC^
In #48..#57) And (PbC^ <>
#0) Do Begin

        TmpStr : = TmpStr + PbC^;
        Inc(PbC);

      End;
      Result :=
StrToInt(TmpStr);
     End ;
Begin
  For i : = 0To Lista.Count - 2Do
  Begin
      small := i;

      smallVal := MyStrToInt(Lista[i]);

       For j : = i + 1To Lista.Count - 1Do
          If MyStrToInt(Lista[j]) <
smallVal
          Then Begin

            small := j;
            smallVal :=
MyStrToInt(Lista[j]);
           End ;

    If small <> i // Permuter
    Then
Begin
      Str : = Lista[i];
      Lista[i] := Lista[small];

      Lista[small] := Str;
     End ;

  End;
End;

Procedure
TFprincipe.Button7Click(Sender: TObject);
Begin
  SortList(ListBox1.Items);
End;
Qui donne un résultat incorrecte :
1 zdhr
1 dbdgh
1 abc
2 acabd
2 aabccd
11
aabccd
111 dkfjgu

Voici ma solution
Procedure
TFprincipe.Button8Click(Sender: TObject);
Var I : Integer;
Begin

  For I : = 0To
ListBox1.Items.Count - 1Do
    ListBox1.Items[I] :=
LeadingZero(ListBox1.Items[I], 4);

  ListBox1.Sorted := True;
End ;

Court simple et éfficace !!!!
<center>Highlighted with Pas2HTML </center>Qui donne un résultat correcte:
001 abc
001 dbdgh
001 zdhr
002 aabccd
002 acabd
011
aabccd
111 dkfjgu

Voilà et si tu veux tester avec ton code Change ceci:

  ARRAY_ADD_ITEM(35,  ' Mon item de valeur 35');
  ARRAY_ADD_ITEM(18,  ' Mon item de valeur 18');
  ARRAY_ADD_ITEM(25,  ' Mon item de valeur 25');
  ARRAY_ADD_ITEM(3,   ' Mon item de valeur 3');
  ARRAY_ADD_ITEM(999, ' Mon 2 item de valeur 999');
  ARRAY_ADD_ITEM(999, ' Mon 1 item de valeur 999');
  ARRAY_ADD_ITEM(-6,  ' Mon item de valeur -6');

 
@+
Cirec

<hr siz ="" />
0
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
20 déc. 2007 à 12:49
"C'est bien ce que je disais
ton code ne fonctionne que si les données sont uniques ...

{ Voici le contenu de la ListBox
1 zdhr
2 acabd
1 dbdgh
1 abc
11 aabccd
2 aabccd
111 dkfjgu
}"

Désolé Cirec, mais si tu testes ma source avec ces éléments lá, mes 2 méthodes fonctionnent très bien (c' est la 3ème fois que je te dis que ça marche) ...

A+
0
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
20 déc. 2007 à 12:58
Tu utilises mal la fonction :
  ARRAY_ADD_ITEM(999, ' Mon

2



item de valeur 999');
  ARRAY_ADD_ITEM(999, ' Mon

1



item de valeur 999');

Doit être écrit: 
  ARRAY_ADD_ITEM(2, ' Mon item de valeur 2');
  ARRAY_ADD_ITEM(1, ' Mon item de valeur 1');

ou même : 
  ARRAY_ADD_ITEM(2, ' Mon item de valeur deux');
  ARRAY_ADD_ITEM(1, ' Mon item de valeur un');
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 déc. 2007 à 13:07
Je ne vois pas ce qu'il y a de juste la dedans !!!!!!!


En rouge c'est le résultat que tu devrais obtenir


Alors ... ou ça marche !!!!!


Et non j'utilise pas mal ta fonction

C'est justement là ou je voulais en venir
Si j'ai mis 1 et 2 dans le texte avec 999 pour les deux c'est que justement la méthode de trie devrait en tenir compte (ce qu'elle ne fait pas)


Si tes chiffres sont unique alors oui ta méthode fonctionne

Mais si il y a des doublons dans les chiffres ... c'est la pagaille
 
@+
Cirec

<hr siz="" />
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 déc. 2007 à 13:10
Vois plus loin que juste les chiffres du début

un trie se fait sur l'ensemble des données si les premières sont identiques

 
@+
Cirec

<hr siz="" />
0
cs_f6dqm1 Messages postés 62 Date d'inscription lundi 8 novembre 2004 Statut Membre Dernière intervention 25 mai 2013
20 déc. 2007 à 13:21
Bjr à tous.
Ne vous battez pas pour si peu !
J'avais bien trouvé la méthode de Cirec consistant à mettre tous le nombres au même format à 3 chiffres mais celà devenait contraignant pour les utilisateurs qui saisissent le contenu des items dans une boite de dialogue.
Chaque item est composé de plusieurs champs séparés par des tabulations, le premier champ étant un nombre de longueur quelconque.
WORD possède une possibilité de tri numérique sur ce type de texte en "tableau" et je m'imaginais qu'il y avait peut-être la même possibilité de tri numérique en Delphi sur une ListBox constituée de la même façon.
Je vais prendre mon courage à deux mains.
Bonne journée à tous
gabriel
0
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
20 déc. 2007 à 13:23
Bem c' est sûr que ça marche pas, il faut reparamétrer la fonction pour tenir compte d' un autre paramètre qui est le texte (qui pourrait être du texte ou un autre integer d' ailleurs dans ma fonction), elle tient compte que de l'integer dans l' exemple.

Il faut juste adapter ici:
        else  // *** Ici on compare des integers, mais on peut comparer tout ce que l' on veut *** //
          if Array_Items[i].Value < Array_Items[RESULT].Value
          then RESULT := i;            // Nouveau item plus petit trouvé !!!

Je vois que tu veux à tout prix avoir raison alors que ta fonction ne fonctionne pas si les chiffres sont à la fin et ainsi, tu imposes le visuel de chaque élément.
A+
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 déc. 2007 à 13:30
Pas de soucis ... on ne se bat pas

Mais c'est toujours difficile de se faire comprendre
"J'avais bien trouvé la méthode de Cirec consistant à mettre tous le
nombres au même format à 3 chiffres mais celà devenait contraignant
pour les utilisateurs qui saisissent le contenu des items dans une
boite de dialogue.
"

Il n'y a rien de contraignant la dedans !

Il suffit de formater. Ex.

I : Integer = 21;

  Format('%.4d', [I]); Renvoie 0021

 
@+
Cirec

<hr siz="" />
0
Rejoignez-nous