StringList.CustomSort

Verweis: stringlisten
Uses: Classes
Eingabe: Einverweis zur Sortierfunktion
Ausgabe: SortErgbnis(Integer)
Funktion: erwartet einen Zeiger auf eine angegebene Sortierfunktion und nimmt 2 Zeilen auf. Als Ergebnis wird nach programmierter Vorgabe sortiert.

Die Funktion CustomSort weicht wesentlich von den Funktionen die wir bisher kennen ab. Hier wird nämlich keine ganze Funktion bereitgestellt sondern nur ein Teil. Dies gibt uns die Möglichkeit diese funktion nach unseren Wünschen zu erweitern. Allerdings ist der Aufruf dieser Funktion nicht ohne.

Beispiel 1

Vorbereitung: Erstellen sie eine IDE Anwendung und ziehen Sie einen TButton und TMemo auf die Form. Binden sie zusätzlich die Unit Math in die Uses-Klausel ein. Doppelklicken sie auf den Button und ersetzen Sie das Ereignis durch folgenden Quelltext:

// unsere Sortier - Funktion
function VergleicheInteger(List: TStringList;
  Index1, Index2: integer): integer;
var
  i1, i2: integer;
begin
  i1 := StrToInt(List[Index1]);
  i2 := StrToInt(List[Index2]);
  Result := CompareValue(i1, i2);
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  zahlen: array[0..4] of string =
    ('4', '11', '9', '023', '44');
var
  Liste: TStringList; //Verknüpfe Variable mit liste
begin
  Liste := TStringList.Create; // Erstelle eine Liste
  //auf keinen Fall sorted := True !
  Liste.Sorted := False;
  //übergebe den Inhalt
  Liste.AddStrings(zahlen);
  Liste.CustomSort(@VergleicheInteger);
  //Im Memo übertragen
  memo1.Lines := Liste;
  // Liste freigeben
  Liste.Free;
end;

In dem Beispiel haben wir eine Funktion mit dem Namen “VergleicheInteger” erstellt. Diese Funktion macht wie der Name schon sagt nur ein Vergleich. Dieser Vergleich wird zwischen 2 Zeilen durchgeführt. Obwohl wir hier keine eigentliche Schleife Programmieren wird die Vergleichsfunktion so oft aufgerufen, bis die liste sortiert ist. Hierbei werden die Einträge nicht verändert sondern nur der Index. Index = die Position des Eintrages in der Liste. Sonst wäre in unserem Beispiel die Null von “023” gelöscht worden. Aber hier nochmal die Funktion im Einzelnen.

function VergleicheInteger(List: TStringList;
  Index1, Index2: integer): integer;
var
  i1, i2: integer;
begin
  i1 := StrToInt(List[Index1]);
  i2 := StrToInt(List[Index2]);
  Result := CompareValue(i1, i2);
end;

Die Funktion nimmt Also die Liste mit den Strings an und 2 Zeilen-Nummern. Als Ergebnis gibt sie einen Integer wert zurück. Wie kann das sein ? Wir haben die Funktion doch so gar nicht aufgerufen. Wir nicht. Aber die Eigenschaft “CustomSort” hat es getan denn wir haben ihr mit dem “@” – Zeichen die Adresse unserer Funktion übergeben. Selbstverständlich können wir hier nicht nach belieben irgendwas übergeben sondern müssen die geforderte Struktur einhalten. Zunächst einmal müssen wir unsere beiden Zeilen in Zahlenwerte Umwandeln. Diese schieben wir mit StrToInt in die Integer – Variablen I1 und I2. Diese Werte können wir jetzt vergleichen. Das machen wir mit dem Befehl “CompareValue” aus der Unit “Math” die wir unbedingt einbinden müssen. Was “CompareValue” macht erfahren sie Hier.

Nochmal der Aufruf

procedure TForm1.Button1Click(Sender: TObject);
const
  zahlen: array[0..4] of string =
    ('4', '11', '9', '023', '44');
var
  Liste: TStringList; //Verknüpfe Variable mit liste
begin
  Liste := TStringList.Create; // Erstelle eine Liste
  //auf keinen Fall sorted := True !
  Liste.Sorted := False;
  //übergebe den Inhalt
  Liste.AddStrings(zahlen);
  Liste.CustomSort(@VergleicheInteger);
  //Im Memo übertragen
  memo1.Lines := Liste;
  // Liste freigeben
  Liste.Free;
end;

Wenn sie also, wie in unserem Beispiel CustomSort auf ein Memo anwenden wollen, dann geht das nicht direkt. Sondern nur über eine Stringliste. Denn eine Möglichkeit wie diese

  memo1.Lines.CustomSort;

gibt es nicht. Also machen wir immer den “Umweg” über die Stringliste, die wir selber erzeugen und auch wieder Freigeben. Nach dem Erstellen der Liste sorgen wir dafür, dass diese mit unseren gewünschten Werten bestückt wird. Dabei ist sicherzustellen das weder in unserer Liste noch in der Zielliste (Memo1) die Eigenschaft “Sorted” auf “True” steht. Dies würde unsere Bemühungen zunichte machen. Nach der Operation können wir den beanspruchten Speicher, unserer temporäre Liste, mit “Free” wieder freigeben.

Zusammenfassung

CustomSort erwartet die Adresse einer Funktion die eine Liste und zwei Indexwerte aufnimmt. Als Ergebnis wird ein Index-Wert mit folgenden Möglichkeiten erwartet:

  • -1: Entspricht I1 < I2
  • 0: Entspricht I1 = I2
  • 1: Entspricht I1 > I2

Nun ruft CustomSort unsere Funktion solange auf, bis alle Werte sortiert sind. Dabei wird weder der Eintrag verändert noch der Eintrag auf Gültigkeit überprüft. Wenn Sie das wollen, dann müssen Sie das extra programmieren.