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
20 déc. 2007 à 13:51
"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."

La tu deviens ridicule

On est parti d'une question donnée
Avec comme élément des chaines à trier qui commencent par des chiffres.
 
J'ai fourni une solution simple et fonctionnel (pour ce cas de figure)
ce qui n'est pas le cas de la tienne. Il m'a fallut plusieurs messages pour que tu remarques ou ça cloche et maintenant tu m'agresses !!!!

Je pourrai en dire de même sur toi dans ce cas ...
Une fois que l'on ta prouvé que ta méthode n'est pas fiable tu t'en prends a la personne ... mais si tu avais été moins dur de la feuille tu l'aurais remarqué dès le début (c'est ce que je te disais dès mon deuxième message et sans tester) et j'ai quand même fait les testes, sur ton code, pour être sur de ce que j'avançais.

Et c'est toi qui me dit que je veux à tout prix avoir raison  ...

Je te rappel que c'est toi qui me relançais à chaque fois pour me dire que ton code donne de bon résultat ... il a fallut un exemple visuel pour te convaincre.

 
@+
Cirec

<hr siz="" />
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 à 14:36
Salut les copains,

Hé ben, on dira qu'il y a de la passion dans les échanges...

Voici la mienne, de routine. Je pense qu'elle répond à la question initialement posée.

Elle répond à ces critères :
- le nombre se trouve au début de la chaîne,
- si plusieurs nombres identiques, classement dans l'ordre alphabétique,
- simplicité d'utilisation, puisque trie directement toute liste descendant de
TStrings, donc utilisable avec TListBox, TComboBox, TMemo, STringList...

Elle ne plante pas sur les chaînes vides et chaînes sans nombre initial.
Je voulais la poster dans les snippets, mais je ne l'ai pas testée à fond et il y a peut-être une faille qui m'aurait échappé.

Vous pouvez vous acharner dessus pour essayer de lui faire cracher ses tripes.

procedure SortByNumber(const List: TStrings);
const
  NumWidth = 6; // 0..999 999 items
var
  TmpList: TStringList;
  i, j: Integer;
  Tmp, Num: string;
begin
  TmpList := TStringList.Create;
  with TmpList do
  try
    Assign(List);
    for i := 0 to Count - 1 do
    begin
      Tmp := Strings[i];
      Num := '';
      j := 1;
      while (j <= Length(Tmp)) and (Tmp[j] in ['0'..'9']) do
      begin
        Num := Num + Tmp[j];
        Inc(j);
      end;
      Num := Format('%.*d', [NumWidth, StrToIntDef(Num, 0)]);
      Strings[i] := Num + Strings[i];
    end;
    Sorted := True;
    Sorted := False;
    for i := 0 to Count - 1 do
    begin
      Strings[i] := Copy(Strings[i], NumWidth + 1, Length(Strings[i]) - NumWidth);
    end;
    List.Assign(TmpList);
  finally
    Free;
  end;
end;

Qu'on peut utiliser ainsi :

procedure TForm1.btnSortClick(Sender: TObject);
begin
  SortByNumber(ListBox1.Items);
end;

Bonne prog'
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 à 14:36
Ok, tu as raison s' il y a des doublons d' entiers combinés avec du texte différent, pas de souci.

D' ailleurs, j' utilise très souvent ta méthode combiné avec l' evenement OnDrawItem pour formater la visualisation. Je voulais apporter quelques chose de nouveau qui n' ai pas la contrainte de formater les items de la listBox.

Par contre, la source que je donne est tout à fait valable, même s' il faut rajouter quelques lignes pour tenir compte du texte dans ce cas de figure ici. Comme tu as pu le voir, elle permet carrément (dans la méthode 2) de dispenser dans la listBox de montrer les chiffres.

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 à 14:53
Salut japee, 
j' aime bien cette solution. 

Une petite remarque:
while (j <= Length(Tmp)) and (Tmp[j] in ['0'..'9']) do
Les items du genre "123 fdgfdg5fg4fd5fdg4fdg" vont être mal traités car il y a des chiffres un peu partout:

Il suffirait de contrôler si on a détecter une coupure de chiffres ...
A+
0

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

Posez votre question
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 à 15:15
Salut Mauricio.

"Les items du genre "123 fdgfdg5fg4fd5fdg4fdg" vont être mal traités car il y a des chiffres un peu partout"

Pas du tout ! La string va se retrouver en position indiquée par le chiffre de début qui est 123, conformément au cahier des charges.
Donc après une éventuelle string commençant par 122, avant une éventuelle string commençant par 124, et s'il y a d'autres string commençant par 123, elles seront classées dans l'ordre alphabétique par rapport aux caractères qui suivent le nombre initial.

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 à 15:20
Haa oui, tu as raison : 
      while (j <= Length(Tmp)) and (Tmp[j] in ['0'..'9']) do

Désolé, je dois être fatigué   lol
A+
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 à 16:25
@Japee
T'as du courage de venir mettre ton grain de sel ici.
T'as pas peur de te chopper un bourre-pif au passage?  mdrrrr

Bon, j'ai torturé ta procedure comme tu nous l'as imprudemment demandé...

Conclusion :
- Très utile pour trier une liste codée de missiles russes.
- Cependant, un petit défaut(?) :
elle classe  .99  avant  0.11 , et ça peut être lourd de conséquence avec des missiles... 

Bref, sinon ça marche impec pour des entiers.
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 à 17:47
Salut Cari,

Oui, j'ai fait l'impasse sur les flottants.
En plus, c'est lent à partir d'un certain nombre d'items.
Utile pour gérer un genre de "playlist", pas plus.
Faudrait pas qu'y ait trop de missiles russes, quoi.
Mais les 3/4 sont rouillés parait-il...

A +

P-S: j'avais mis un casque intégral avant de me risquer.
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 à 18:23
Une dernière version qui règle le problème des missiles balistiques Russe

En fait la précédente version le faisait correctement mais pour ne pas changer les données d'origine (Zéros en plus) cette version (tout comme celle de Japee) restitue fidèlement les données

Je vous remet la fonction LeadingZero mais c'est la même qu'avant !

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;

Procedure SortByNumber2(List:
TStrings);
Const
  NumWidth = 6; // 0..999 999 items
Var
  TmpList, FinalList: TStringList;

  I: Integer;
Begin
  TmpList : =
TStringList.Create;
   With TmpList Do Try
   BeginUpdate;
    For I : = 0To List.Count - 1Do
    AddObject(LeadingZero(List.Strings[I]),
TObject(I));
    Sorted := True;
    EndUpdate;
  FinalList :=
TStringList.Create;
   With FinalList Do Try
    BeginUpdate;
    For I : = 0To List.Count - 1Do

      Add(List.Strings[Integer(TmpList.Objects[I])]);

    EndUpdate;
  Finally

    List.Assign(FinalList);
    Free;
  End;
  Finally

    Free;
  End;
End;

Procedure
TFprincipe.Button10Click(Sender: TObject);
Begin
  SortByNumber2(ListBox1.Items);
End;
<center>Highlighted with Pas2HTML </center>

 
@+
Cirec

<hr siz="" />
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 à 19:00
Salut Cirec,

Perso, je n'ai pas trouvé que BeginUpdate et EndUpdate faisaient gagner du temps, alors je les ai virés.
D'après un test rapide, nos routines sont sensiblement équivalentes au niveau du temps de traitement. Et elles commencent à ramer à partir de plusieurs dizaines de milliers d'items.
Mais là ça commence à faire du monde dans une ListBox, hein ?

A +
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 à 19:02
"Perso, je n'ai pas trouvé que BeginUpdate et EndUpdate faisaient gagner du temps, alors je les ai virés."

Enfin, dans ma routine, je voulais dire... je me suis pas permis pour la tienne
(mais ça doit être pareil, sans doute, je vais vérifier...)
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 à 19:05
Je viens de vérifier sur une liste de 9999 items, la différence n'est pas significative.
D'autant que le temps de traitement est assez variable de toute manière, selon le degré de mélange des items certainement.
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 à 19:06
Oui c'est vrai que Begin/End Update n'y change rien

J'irais même plus loin en affirmant que ma procédure est ~ 1 seconde plus lente sur 10 000 requêtes que la tienne.
tout le temps que je gagne avec ma fonction LeadingZero je le perd en utilisant une StringList supplémentaire

 
@+
Cirec

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