Objectlist sortieren

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Objectlist sortieren

Beitrag von mulcheo »

Hallo zusammen,

ich komm nicht weiter, leider.
Ich möchte eine Objectlist sortieren und habe dazu eine Funktion geschrieben, die ich per sort aufrufen möchte. Aber mein Compiler will nicht und meint 'wrong number of parameters' etc. Ich habe dutzende Threads und 'examples' durchsucht, sehe aber einfach nicht, was bei mir schief läuft.

die wichtigen Teile, denke ich, sind Deklaration und Aufrufe - also hier:

Code: Alles auswählen

interface

uses
  Classes, SysUtils, Graphics,
  StrUtils, Testing, Pfade, Contnrs;

type

TMarkerliste = class(TObjectlist)
    function Vergleiche(item1: Pointer; item2: Pointer): integer;   
end;

[...]

implementation

function TMarkerliste.Vergleiche(item1: Pointer; item2: Pointer): integer;

var
  A,B: TDBMarker;

begin
  A:=TDBMarker(item1);  B:=TDBMarker(item2);
  if (A.Orig.Zeile < B.Orig.Zeile) then result:= -1;
  if (A.Orig.Zeile > B.Orig.Zeile) then result:= 1;
  if (A.Orig.Zeile = B.Orig.Zeile) then begin
    if (A.Orig.Element < B.Orig.Element) then result:= -1;
    if (A.Orig.Element > B.Orig.Element) then result:= 1;
  end;
end;

[...]

procedure TM.sortieren;

var
  i: integer;

begin
  Markerliste:=TMarkerliste.Create;
  for i:=1 to High(DB) do begin
    MarkerListe.Add(DB[i]);
  end;
  Markerliste.Sort(M.Markerliste.Vergleiche);   // hier meckert der compiler
end;                              

vielleicht könnt ihr helfen.
Grüße.

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Objectlist sortieren

Beitrag von wp_xyz »

In der Dokumentation zu TFpObjectList.Sort (https://www.freepascal.org/docs-html/cu ... .sort.html) findest du, dass die Methode Sort() als Parameter die Adresse einer Funktion benötigt, die vom Typ TListSortCompare sein muss. Und TListSortCompare ist deklariert als:

Code: Alles auswählen

type
  TListSortCompare = function (Item1, Item2: Pointer): Integer;  
Deine Vergleichsfunktion hat zwar scheinbar dieselbe Parameterabfolge, ist jedoch als Methode einer Klasse deklariert. Das ist etwas anderes, denn diese enthält ein "unsichtbares" Argument "self" in der Parameterliste (daher die Fehlermeldung wegen des unterschiedlichen Parameteranzahl). Die Deklaration müsste am Ende ein "of object" enthalten:

Code: Alles auswählen

type
  TListSortCompare_Methode = function (Item1, Item2: Pointer): Integer of object; 
Daher musst du deine Vergleichsfunktion aus der Klasse herausnehmen und als "freistehende" Funktion deklarieren.

Code: Alles auswählen

type
TMarkerliste = class(TObjectlist)
end;

[...]

implementation

function Vergleiche(item1: Pointer; item2: Pointer): integer;
var
  A,B: TDBMarker;
begin
  A:=TDBMarker(item1);  B:=TDBMarker(item2);
  if (A.Orig.Zeile < B.Orig.Zeile) then result:= -1;
  if (A.Orig.Zeile > B.Orig.Zeile) then result:= 1;
  if (A.Orig.Zeile = B.Orig.Zeile) then begin
    if (A.Orig.Element < B.Orig.Element) then result:= -1;
    if (A.Orig.Element > B.Orig.Element) then result:= 1;
  end;
end;
Ein Hinweis noch: In der Hilfe zu TFPObjectList.Sort steht ganz unten, dass die Sortierfunktion mit nil-Werten umgehen können muss. Das ist bei dir nicht der Fall. Wenn item1 und/oder item2 als nil übergeben werden, krachts...

mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Re: Objectlist sortieren

Beitrag von mulcheo »

super danke,

ich hab gerade selbst 'gemerkt', dass es geht, wenn ich die funktion aus der Klasse rausnehme und ein @ in in den Aufruf hineinnehme, also:

Code: Alles auswählen

MarkerListe.Sort(@Vergleiche)
dank dir versteh ich jetzt auch das Problem 'Teil einer Klasse'. Was hat es mit dem @ auf sich?

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Objectlist sortieren

Beitrag von wp_xyz »

Der Typ TListSortCompare ist die Adresse einer Funktion (mit bestimmter Parameterabfolge), also ein Pointer. Daher braucht man den Adress-Operator @ um den Pointer auf diese Funktion zu bestimmen. Kompliziert wird's nur, weil Delphi die Sprache Pascal "vereinfacht" hat und durch allerlei Tricks verschleiert, welche Variablen/Argumente Pointer sind. Daher muss man in Delphi das @ weglassen. Und wenn man am Kopf einer Lazarus-Unit ein {$Mode Delphi} hat, dann muss man das auch bei Lazarus so machen. Bleibt man jedoch bei der Standardeinstellung {$Mode fpcobj}, dann ist das @ verpflichtend.

mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Re: Objectlist sortieren

Beitrag von mulcheo »

okay, dann muss ich nur noch rausfinden, warum ich beim Ausführen ne AV bekomme. Ich bin mir recht sicher, dass ich keine nils in der Objectlist habe, zumindest habe ich den Zugriff auf alle items via Ausgabe in ein Memo getestet...

Code: Alles auswählen

Markerliste:=TMarkerliste.Create;
  for i:=1 to High(DB) do begin
    MarkerListe.Add(DB[i]);
    if DB[i] = nil then Form2.Memo1.Lines.Add(IntToStr(i));
    Form2.Memo3.Lines.Add(IntToStr(DB[i].Orig.Zeile)+'/'+IntToStr(DB[i].Orig.Element));
  end;
  Form2.Memo1.Lines.Add(IntToSTR(Markerliste.Count));
  for i:=0 to Markerliste.Count-1 do begin
    Form2.Memo2.Lines.Add(IntToStr(TDBMarker(Markerliste.Items[i]).Orig.Zeile)+'/'+IntToStr(TDBMarker(Markerliste.Items[i]).Orig.Element));
  end;
 // Markerliste.Sort(@VERGLEICH); 
end;                           
läuft reibungslos. wenn ich dann Markerliste.Sort(@Vergleich); zuschalte bekomme ich eine AV...

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Objectlist sortieren

Beitrag von wp_xyz »

Ich hab den QuickSort jetzt nicht im Kopf, aber ich meine, dass da auch mit nil verglichen werden kann, auch wenn nil gar nicht in der Liste enthalten ist. Schreib mal die Vergleichsfunction inkl nil-Behandlung, also: was ist das Vergleichsergebnis, wenn beide Items nil sind (0), wenn Item1=nil ist (-1?), und wenn Item2=nil (+1 ?). Erst dann kommt dein jetziger Code.

Antworten