AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language FreePascal Delphi Listbox Items nach Teil String sortieren

Delphi Listbox Items nach Teil String sortieren

Ein Thema von Zeref Darkmage · begonnen am 22. Dez 2017 · letzter Beitrag vom 1. Jan 2018
Antwort Antwort
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.100 Beiträge
 
Delphi XE2 Professional
 
#1

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 24. Dez 2017, 01:40
@Zeref:
Ein Weihnachtsgeschenk für dich:

Delphi-Quellcode:
PROCEDURE SortListBoxBubbleSort(List:TStrings; Dsc:Boolean);
FUNCTION Compare(const A,B:String):Integer;
begin
   Result:=Pos(' ',A)-Pos(' ',B);
   if Result=0 then Result:=CompareStr(A,B);
   if Dsc then Result:=-Result;
end;
var I,First,Last:Integer; Sorted:Boolean; H:String;
begin
   List.BeginUpdate;
   First:=0;
   Last:=List.Count-1;
   repeat
      Dec(Last);
      Sorted:=true;
      for I:=First to Last do
         if Compare(List[I],List[I+1])>0 then begin
            Sorted:=false;
            H:=List[I];
            List[I]:=List[I+1];
            List[I+1]:=H;
         end;
   until Sorted;
   List.EndUpdate;
end;
Aufruf:
SortListBoxBubbleSort(ListBox1.Items,True);

Der zweite Parameter gibt an, ob die Liste aufsteigend (False) oder absteigend sortiert wird (True).

Achtung:
Das funktioniert nur, wenn alle Einträge mit einer vorzeichenlosen Ganzzahl ohne führende 0 beginnen und dieser Zahl ein Blank folgt.
Die Compare Funktion gibt 0 zurück wenn A = B ist, einen positiven Wert wenn A > B ist und einen negativen Wert, wenn A < B ist.


Wenn die Liste nur wenig Einträge hat (200 oder so) dann sollte die obige Version OK sein.
Bei mehr Einträgen hier die Quicksort-Version:

Delphi-Quellcode:
PROCEDURE SortListBoxQuickSort(List:TStrings; Dsc:Boolean);
FUNCTION Compare(const A,B:String):Integer;
begin
   Result:=Pos(' ',A)-Pos(' ',B);
   if Result=0 then Result:=CompareStr(A,B);
   if Dsc then Result:=-Result;
end;
var M,H:String;
PROCEDURE QSort(First,Last:Integer);
var I,J:Integer;
begin
   I:=First;
   J:=Last;
   M:=List[(First+Last) shr 1];
   repeat
      while Compare(List[I],M)<0 do Inc(I);
      while Compare(List[J],M)>0 do Dec(J);
      if I<=J then begin
         H:=List[I];
         List[I]:=List[J];
         List[J]:=H;
         Inc(I);
         Dec(J);
      end;
   until i>j;
   if J>First then QSort(First,J);
   if I<Last then QSort(I,Last);
end;
begin
   List.BeginUpdate;
   QSort(0,List.Count-1);
   List.EndUpdate;
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Solutor

Registriert seit: 24. Dez 2017
15 Beiträge
 
Delphi XE2 Enterprise
 
#2

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 24. Dez 2017, 12:12
Das ist eine häufig benötigte Funktion.
Ich habe mal einen Lösungsvorschlag mit mehreren Varianten und hoffe ich ausreichenden Kommentaren.
Hiermit lassen sich die komplexesten Sortier Varianten erstellen, was ish selbst z.B. dazu verwende eine komplett im Arbeitsspeicher
vorgehaltene Musikdatenbank nach den verschiedensten Kriterien zu sortieren, was bei mehreren 10000 Einträgen rasant schnell funktioniert.

Es werden benötigt:
Eine Form mit, 1 Listbox und 2 Buttons.
Keine besondere Uses Anweisung notwendig.


Also los gehts:
//================================================== ================================================== =================
// Die eigentliche Sortier-Callback Funktion die an TStringlist übergeben werden kann.
// Es werden die eigentliche Liste, sowie zwei Indizes der Liste an die Funktion übergeben.
// Man muss nun die beiden Elemente der Liste miteinander Vergleichen,
// die über die Indizes zur Verfügung gestellt werden.
//
// Dazu muss man also folgendes tun:
// Ist das Element der Liste mit dem Index1 größer als das Element der Liste mit dem Index2,
// so muss man als Rückgabeparameter dieser Funktion eine 1 einsetzen.
//
// Ist das Element der Liste mit dem Index1 kleiner als das Element der Liste mit dem Index2,
// so muss man als Rückgabeparameter dieser Funktion eine -1 einsetzen.
//
// Sind beide Elemente gleich,
// so muss man als Rückgabeparameter dieser Funktion eine 0 einsetzen.
//
// Der eigentliche Sortieralgorithmus ist dann Quicksort, der vom Objekt TStringlist
// auf die hier gezeigte Weise zur Verfügung steht.
// Man kann anstelle der Strings auch in gewohnter Weise auf die Objektliste zugreifen.
// z.B. TIrgendetwas(List.Objects[index1])
//
// Ich habe hier beim Vergleichen die ausführliche Schreibweise der If Anweisungen gewählt.
// Bei einem Einfachen Vergleich ist das zwar nicht nötig, doch bei Erweiterungen bietet
// die Variante mit dem "Exit" in den jeweiligen Zweigen vielfältige Möglichkeiten um
// z.B. verschachtelt zu sortieren. (Wie man es z.b.von Excel kennt - Erst nach Spalte A dann nach Spalte C.... usw.)
//================================================== ================================================== =================


//================================================== ================================================== =================
// Variante 1
// Die Führenden Ziffern des Strings als Integer interpretieren und danach sortieren, wie es eigentlich snnvoll ist.
//================================================== ================================================== =================
Function MySortByNumbersAsValue(list:TStringlist;Index1:Int eger;Index2:Integer):Integer;
Var A,B:Integer;
begin
Result:=0;//Defaultrückgabewert auf 0 setzen.
a:=StrToInt(Copy(list[index1],1,Pos(#32,(list[index1]))-1));
b:=StrToInt(Copy(list[index2],1,Pos(#32,(list[index2]))-1));
if A>B then
begin
Result:=1;
Exit;
end;
if A<B then
begin
Result:=-1;
Exit;
end;
end;

//================================================== ================================================== =================
// Variante 2
// Einfach die Strings sortieren wie sie sind, wie es z.b. der Explorer mit Dateinamen macht, was aber nicht immer schön ist.
//================================================== ================================================== =================
Function MySortByFirstChars(list:TStringlist;Index1:Integer ;Index2:Integer):Integer;
Var A,B:String;
begin
Result:=0;
a:=list[index1];
b:=list[index2];
if A>B then
begin
Result:=1;
Exit;
end;
if A<B then
begin
Result:=-1;
Exit;
end;
end;

//================================================== ================================================== =================
// Aufruf - Sortieren der Liste nach Nummern
// Die wesentliche Zeile ist die mit "CustomSort"
//================================================== ================================================== =================
procedure TForm1.Button1Click(Sender: TObject);
Var l:Tstringlist;
begin
l:=TStringlist.Create;//Hilfsliste erzeugen
Listbox1.Items.BeginUpdate;//Listbox Zeichnen einfrieren
l.Assign(Listbox1.items);//Inhalt der Listbox in die Hilfsliste kopieren
l.CustomSort(MySortByNumbersAsValue);//Hilfsliste sortieren, wobei die führenden ziffern in Zahlen umgewandelt wurden.
Listbox1.Items.Assign(L);//Hilfsliste zurück in die Listbox kopieren
l.free;//Hilfsliste wieder freigeben
Listbox1.Items.EndUpdate;//Listbox Zeichnen wieder freigeben
end;

//================================================== ================================================== =================
// Aufruf - Sortieren der Liste nach dem kompletten String - also ganz normal aber unelegant.
// Die wesentliche Zeile ist die mit "CustomSort"
//================================================== ================================================== =================
procedure TForm1.Button2Click(Sender: TObject);
Var l:Tstringlist;
begin
l:=TStringlist.Create;//Hilfsliste erzeugen
Listbox1.Items.BeginUpdate;//Listbox Zeichnen einfrieren
l.Assign(Listbox1.items);//Inhalt der Listbox in die Hilfsliste kopieren
l.CustomSort(MySortByFirstChars);//Hilfsliste einfach nach Zeichen sortieren wie in einem Telefonbuch
Listbox1.Items.Assign(L);//Hilfsliste zurück in die Listbox kopieren
l.free;//Hilfsliste wieder freigeben
Listbox1.Items.EndUpdate;//Listbox Zeichnen wieder freigeben
end;


//================================================== ================================================== =================
//Füllen der Listbox mit Zufallswerten für den Test um was zum Spielen zu haben
//================================================== ================================================== =================
procedure TForm1.FormCreate(Sender: TObject);
Var i,j:Byte;
h:string;
begin
Listbox1.Items.BeginUpdate;//Listbox Zeichnen einfrieren
for i:= 1 to 100 do
begin
h:=Inttostr(Random(1000))+' ';
for j:=1 to Random(10)+5 do
begin
h:=h+Char(Random(25)+65);
end;
h:=h+' ';
h:=h+Inttostr(Random(1000))+' ';
for j:=1 to Random(10)+5 do
begin
h:=h+Char(Random(25)+65);
end;
Listbox1.Items.add(h);
end;
Listbox1.Items.EndUpdate;//Listbox Zeichnen wieder freigeben
end;
  Mit Zitat antworten Zitat
Solutor

Registriert seit: 24. Dez 2017
15 Beiträge
 
Delphi XE2 Enterprise
 
#3

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 24. Dez 2017, 12:14
Sorry! Das mit dem Quellcode Einfügen hab ich noch nicht so richtig drauf.
Bin noch neu im Forum.
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.437 Beiträge
 
Delphi 12 Athens
 
#4

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 24. Dez 2017, 12:17
Moin...

Da gehst du in erweiteren Beitrag bearbeiten, markierst den Quelltext und drückst dem Button mit dem Helm...

Code ist für z.B. XML gedacht. Der Helm ist für Delphi Quelltext...
  Mit Zitat antworten Zitat
Solutor

Registriert seit: 24. Dez 2017
15 Beiträge
 
Delphi XE2 Enterprise
 
#5

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 24. Dez 2017, 12:16
So das Ganze noch einmal:

Code:
//=====================================================================================================================
// Die eigentliche Sortier-Callback Funktion
// Hier werden die eigentliche Liste, sowie zwei Indizes der Liste zur Verfügung gestellt.
// Man muss nun die beiden Elemente der Liste miteinander Vergleichen,
// die über die Indizes zur Verfügung stehen.
//
// Ist das Element der Liste mit dem Index1 größer als das Element der Liste mit dem Index2,
// so muss man als Rückgabe Parameter dieser Funktion eine 1 einsetzen.
//
// Ist das Element der Liste mit dem Index1 kleiner als das Element der Liste mit dem Index2,
// so muss man als Rückgabe Parameter dieser Funktion eine -1 einsetzen.
//
// Sind beide Elemente gleich,
// so muss man als Rückgabe Parameter dieser Funktion eine 0 einsetzen.
//
// Der eigentliche Sortieralgorithmus ist Quicksort, der vom Objekt TStringlist,
// auf die hier gezeigte Weise zur Verfügung steht.
// Man kann sogar in gewohnter Weise auf die Objektliste zugreifen.
// z.B. TIrgendetwas(List.Objects[index1])
//
// Ich habe hier beim Vergleichen die ausführliche Schreibweise der If Anweisungen gewählt.
// Bei einem Einfachen Vergleich ist das zwar nicht nötig, doch bei Erweiterungen bietet
// die Variante mit dem "Exit" in den jeweiligen Zweigen vielfältige Möglichkeiten um
// z.B. verschachtelt zu sortieren. (Wie man es z.b.von Excel kennt - Erst nach Spalte A dann nach Spalte C.... usw.)
//=====================================================================================================================


// Die Führenden Ziffern des Strings als Integer interpretieren und danach sortieren, wie es eigentlich snnvoll ist.
Function MySortByNumbersAsValue(list:TStringlist;Index1:Integer;Index2:Integer):Integer;
Var A,B:Integer;
begin
   Result:=0;
   a:=StrToInt(Copy(list[index1],1,Pos(#32,(list[index1]))-1));
   b:=StrToInt(Copy(list[index2],1,Pos(#32,(list[index2]))-1));
   if A>B then
   begin
      Result:=1;
      Exit;
   end;
   if A<B then
   begin
      Result:=-1;
      Exit;
   end;
end;

// Einfach die Strings sortieren wie sie sind, wie es z.b. der Explorer mit Dateinamen macht.
Function MySortByFirstChars(list:TStringlist;Index1:Integer;Index2:Integer):Integer;
Var A,B:String;
begin
   Result:=0;
   a:=list[index1];
   b:=list[index2];
   if A>B then
   begin
      Result:=1;
      Exit;
   end;
   if A<B then
   begin
      Result:=-1;
      Exit;
   end;
end;

//=====================================================================================================================
//Sortieren der Liste nach Nummern
//=====================================================================================================================
procedure TForm1.Button1Click(Sender: TObject);
Var l:Tstringlist;
begin
   l:=TStringlist.Create;//Hilfsliste erzeugen
   Listbox1.Items.BeginUpdate;//Listbox Zeichnen einfrieren
   l.Assign(Listbox1.items);//Inhalt der Listbox in die Hilfsliste kopieren
   l.CustomSort(MySortByNumbersAsValue);//Hilfsliste sortieren, wobei die führenden ziffern in Zahlen umgewandelt wurden.
   Listbox1.Items.Assign(L);//Hilfsliste zurück in die Listbox kopieren
   l.free;//Hilfsliste wieder freigeben
   Listbox1.Items.EndUpdate;//Listbox Zeichnen wieder freigeben
end;

//=====================================================================================================================
//Füllen der Listbox mit Zufallswerten für den Test
//=====================================================================================================================

procedure TForm1.Button2Click(Sender: TObject);
Var l:Tstringlist;
begin
   l:=TStringlist.Create;//Hilfsliste erzeugen
   Listbox1.Items.BeginUpdate;//Listbox Zeichnen einfrieren
   l.Assign(Listbox1.items);//Inhalt der Listbox in die Hilfsliste kopieren
   l.CustomSort(MySortByFirstChars);//Hilfsliste einfach nach Zeichen sortieren wie in einem Telefonbuch
   Listbox1.Items.Assign(L);//Hilfsliste zurück in die Listbox kopieren
   l.free;//Hilfsliste wieder freigeben
   Listbox1.Items.EndUpdate;//Listbox Zeichnen wieder freigeben
end;

procedure TForm1.FormCreate(Sender: TObject);
Var i,j:Byte;
    h:string;
begin
   Listbox1.Items.BeginUpdate;//Listbox Zeichnen einfrieren
   for i:= 1 to 100 do
   begin
      h:=Inttostr(Random(1000))+' ';
      for j:=1 to Random(10)+5 do
      begin
         h:=h+Char(Random(25)+65);
      end;
      h:=h+' ';
      h:=h+Inttostr(Random(1000))+' ';
      for j:=1 to Random(10)+5 do
      begin
         h:=h+Char(Random(25)+65);
      end;
      Listbox1.Items.add(h);
   end;
   Listbox1.Items.EndUpdate;//Listbox Zeichnen wieder freigeben
end;
  Mit Zitat antworten Zitat
Solutor

Registriert seit: 24. Dez 2017
15 Beiträge
 
Delphi XE2 Enterprise
 
#6

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 24. Dez 2017, 12:23
Ein paar Erläuterungen zu meiner Arbeitsweise:
Listbox Co. verwende ich in der Regel nur zur Anzeige und dann mit OwnerDraw.
Meine Daten selbst halte ich immer in Stringlisten vor, wobei ich hier maist die Objektliste verwende.
Aus diese Weise lassen sich einzelne Datenelemente einfach und vor Allem schnell suchen, sortieren, und manipulieren.
Ergänzungen an der Struktur, dem Verhalten und der Visualisierung sind so viel einfacher und flexibler.
Einziger Nachteil ist der Aufwand beim Erstellen der Grundstruktur. Dieser Nachteil ist bereits nach kurzer Zeit ausgeglichen.
  Mit Zitat antworten Zitat
Zeref Darkmage
(Gast)

n/a Beiträge
 
#7

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 31. Dez 2017, 16:01
Hi da bin ich wider. Nach dem alles super funktioniert hat bin ich wider da und knüpfe an diesem Beitrag eine Frage an und hoffe das sie gelesen wird ^^ . Dachte dass ich kein neuen Thread

aufmachen muss wenn die Frage zum Programm gehört. Falls es doch erwünscht ist mache ich es natürlich ^^


folgendes: ich möchte mit Listbox1.items.LoadFromFile(); mehrere txt datein einlesen,

71524 Tobi 7623 Müller
292748 Max 872 Müller
89237 Lucas 8723 Müller

diese Datein beinhalten alle Zeilenweise die gleiche Syntax, soweit kein Problem für mich wenn ich im Quelltext bei LoadFromFile den Pfad explizit angebe. Allerding sind das datein welche zwar

alles z.b Liste.txt heißen allerdings

da es mehere sind würden sie bei mir entweder umbenannt werden damit sie im selben Pfad liegen können oder bekommen Liste(1).txt,Liste(2).txt... als namen.

In jedem fall würde es so nicht im Quelltext drin stehen. Heißt ich brauche eine Möglichkeit wie ich flexibel die txt datein laden kann .



hat jemand für mich deswegen vllt ein paar stichworte nach dem ich im Web suchen muss

Lg Zeref

Geändert von Zeref Darkmage (31. Dez 2017 um 16:02 Uhr) Grund: änderung
  Mit Zitat antworten Zitat
LTE5

Registriert seit: 13. Nov 2017
355 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#8

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 31. Dez 2017, 16:07
Zitat:
In jedem fall würde es so nicht im Quelltext drin stehen. Heißt ich brauche eine Möglichkeit wie ich flexibel die txt datein laden kann .
Du hast dir deine Antwort schon selber gegeben
Zitat:
soweit kein Problem für mich wenn ich im Quelltext bei LoadFromFile den Pfad explizit angebe.
  Mit Zitat antworten Zitat
Zeref Darkmage
(Gast)

n/a Beiträge
 
#9

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 31. Dez 2017, 16:34
wenn ich sage:"In jedem fall würde es so nicht im Quelltext drin stehen. Heißt ich brauche eine Möglichkeit wie ich flexibel die txt datein laden kann ."

ist gemeint, wie auch sonst, dass ich eine Möglichkeit brauche wie ich sie flexibel laden kann



und wenn ich sage das ich sie flexibel laden möchte und hier aber steht:"

soweit kein Problem für mich wenn ich im Quelltext bei LoadFromFile den Pfad explizit angebe."

ist mit explizit gemeint, wie auch sonst, dass es eben nicht flexibel ist

und ich nicht weiterkomme

lg
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.558 Beiträge
 
Delphi 7 Professional
 
#10

AW: Delphi Listbox Items nach Teil String sortieren

  Alt 31. Dez 2017, 16:36
Nehmen wir an, dass die Dateien mit beliebigen Namen alle in einem Verzeichnis liegen, dann könntest Du recht einfach mit FindFirst arbeiten.

Oder wäre ein Dialog eine Alternative?

Ein Dateiauswahldialog, den so konfigurieren, dass mehrere Dateien ausgewählt werden können und diese dann alle laden. (Klingt komplizierter, als es ist.)

Einen Dialog nutzen, der "nur" zur Auswahl eines Verzeichnisses dient und dann im ausgewählten Verzeichnis alle Dateien lesen ...

Mit LoadFromFile kann man aber nicht mehrere Dateien gleichzeitig laden, sondern immer nur eine.

Aber: Items ist vom Typ TStrings und hat die Methode AddStrings. Damit kann man den Inhalt einer Stringliste zu den vorhandene Items hinzufügen. Grob ungefähr sowas (ungetestet hingedaddelt):
Delphi-Quellcode:
var
  sl : TStringList;
  sr : TSearchRec;
begin
  sl := TStringList.Create;
  Listbox1.Items.Clear;
  // Statt Liste*.txt irgendeinen Namensplatzhalter nach eigenen Wünschen.
  // Ggfls. auch noch 'nen Pfad mit angeben.
  If FindFirst('Liste*.txt',faAnyFile,sr) = 0 then begin
    Repeat
      sl.LoadFromFile(sr.Name);
      Listbox1.Items.AddStrings(sl);
    until FindNext(sr) <> 0;
  end;
  FindClose(sr);
  sl.Free;
end;
  Mit Zitat antworten Zitat
Antwort Antwort

 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:03 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz