18. marts 2004 - 14:25Der er
6 kommentarer og 1 løsning
sortering af multi array
Hejsa
jeg har følgende array:
array_ting: array of array[0..1] of string;
jeg fylder dette array med data fra en database.. og placerer dem ved:
with Form1.Myquery1 do begin while not EOF do begin array_ting[i, 0] := Form1.Myquery1.fieldbyname('indeks').asstring; array_ting[i, 1] := Form1.Myquery1.fieldbyname('navn').asstring; end; end;
..jeg vil meget gerne sortere mit array efter "indeks" værdierne.. dvs.. de værdier som er placeret som array_ting[i, 0]...
for at skære det HELT ud i pap.. så vil jeg gerne have følgende output:
Her er kode som viser hvordan man sorterer et 2D array af integers efter kolonnen med index 3:
program MultiDimSort;
{$APPTYPE CONSOLE}
uses SysUtils;
type mda = array of array of integer;
procedure init(var a : mda; n, m : integer);
var i, j : integer;
begin randomize; setlength(a, n); for i := low(a) to high(a) do begin setlength(a[i], m); for j := low(a[i]) to high(a[i]) do begin a[i,j] := random(100); end; end; end;
procedure print(var a : mda);
var i, j : integer;
begin for i := low(a) to high(a) do begin for j := low(a[i]) to high(a[i]) do begin write(' ', a[i,j]); end; writeln; end; end;
procedure sort(var a : mda);
var i, j, k, tmp : integer;
begin for i := low(a) to (high(a) - 1) do begin for j := (i + 1) to high(a) do begin if a[i,3] > a[j,3] then begin for k := low(a[i]) to high(a[i]) do begin tmp := a[i,k]; a[i,k] := a[j,k]; a[j,k] := tmp; end; end; end; end; end;
var a : mda;
begin init(a, 10, 5); writeln('before'); print(a); sort(a); writeln('after'); print(a); end.
Hvorfor lave det på den måde? Hvorfor ikke lave et TPerson objekt og fylde dem ind i en TObjectList (jeg gentager mig selv, ved det godt). Nedenstående genererer en liste på grundlag af resultatet af aQDOQuery.
Din Person Unit: ----------------
type TPerson = class private fID : integer; fName : string; public constructor Create(aId : integer; aName : string); property ID : integer read fID; property Name : string read fName; end;
function TPersonList.GetPerson(aIndex : integer) : TPerson; begin result := TPerson(inherited Items[aIndex]); end;
constructor TPersonList.Create(aQuery : TADOQuery); begin inherited Create;
aQuery.First; while not aQuery.Eof do begin Add(TPerson.Create(aQuery.FieldByName('ID').AsInteger, aQuery.FieldByName('Name').AsString)); aQuery.Next; end; // while end;
function SortPerson(aItem1, aItem2 : pointer) : integer; var p1, p2 : TPerson; begin p1 := aItem1; p2 := aItem2;
if p1.Name < p2.Name then // First try sorting by name result := 1 else if p1.Name > p2.Name then result := -1 else begin // If same the try sort by ID if p1.ID < p2.ID then result := 1 else if p2.ID > p2.ID then result := -1 else // The're alike. result := 0; end; end;
procedure TPersonList.Sort; begin inherited Sort(SortPerson); end;
procedure Form1.OnDestroy(aOwner : TObject); begin fPersonList.Free; end;
procedure Form1.OnButtonClick(aOwner : TObject); var i : integer; Person : TPerson; begin fPersonList.Sort; // Sort the list...
for i := 0 to fPersonList.Count - 1 do begin Person := fPersonList[i]; Memo1.Lines.Add(format('%d: %s',[Person.Id,Person.Name])); end; // for end;
Det er noget smukkere end den løsning du har valgt og den er meget, meget mere fleksibel, hvis f.eks. du vil tilføje et adresse felt. Selvom det er simpel indkapsling, så ser det helt objektorienteret ud.
Du må endelig spørge løs hvis du er interesseret i løsningen. Der jeg er meget glad for at vise denne løsning (som jeg har gjort 1-2 allerede).
Humlen i ovenstående eksempel er den lille funktion: SortPerson som ikke hører til klasserne. Den fodrer man fObjectList.Sort-proceduren og så sorteres listen - lynhurtigt.
Idet du skal have listen sorteret efter id og navn (i den rækkefølge) så skal SortPerson se sådan her ud:
function SortPerson(aItem1, aItem2 : pointer) : integer; var p1, p2 : TPerson; begin p1 := aItem1; p2 := aItem2;
// First compare ID's if p1.ID < p2.ID then result := 1 else if p2.ID > p2.ID then result := -1 else begin // The're alike. Try names instead. if p1.Name < p2.Name then result := 1 else if p1.Name > p2.Name then result := -1 else result := 0; end; end;
ADOQuery1.Sql := 'select id, name from person order by id, name';
Egentlig burde TPersonList.Create kaldes med TADOConnection så objektet kunne oprette en TADOQuery selv - den behøver ikke findes på mainform'en.
Det gik vist lidt hurtigt med en af de afsluttende kommentarer: Du må endelig spørge løs hvis du er interesseret i løsningen, da jeg er meget glad for at vise denne løsning (som jeg har gjort det 1-2 gange allerede).
PUha.. jeg ved næsten ikke hvor jeg skal begynde..
Først vil jeg lige prøve at nørkle lidt med det selv.. også vil jeg vende tilbage.. med nogle mere præcise spørgsmål. Jeg har aldrig prøvet at kode på denne facon - men det ser smart ud.!
Tror det kaldes let objektorienteret programmering ;-) Der er mange forskellige lister i Delphi og TObjectList er en af de bedre. Når du nedlægger den, så fjernes objekterne på listen automatisk. Det mest normale alternativ er TList'en, men her skal man selv frigive de objekter der må sidde på listen:
destructor MyList.Destroy() var i : integer; begin try for i := Count - 1 downto 0 do TObject(Items[i]).Free; finally inherited; end; end;
De andre steder hvor der slettes (delete og remove) skal man lave samme operation på en nedarvet klasse.
Eneste anke med TObjectList er at dens constructor tager en boolsk parameter der angiver om listen ejer de objekter man hælder i den eller om de frigives andetsteds. Har kigget i VCL-koden og den har p.t. ingen betydning. Ulempen er, at det kan den pludselig få og man skal være opmærksom på dette ved opdatering. Jeg burde have oprettet sådan: fPersonList := TPersonList.Create(true); men det glemte jeg.
Jeg kan godt sende dig et eksempel hvis du vil se det (uden ADO), men med en liste over drenge og pigenavne. Skriv til: hrc_public snabela hotmail dot com
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.