![]() |
Feld sortieren und damit weiterarbeiten
Hallo zusammen,
nach langer Zeit bin ich mal wieder hier unterwegs und hab auch wieder eine Frage :) Der Titel ist evtl. etwas blöd, aber ich weiß nicht, wie ich das anders kurz in Worte fassen soll :stupid: Ich hab eine Klasse, die ein Datenarray enthält. Das möchte ich sortieren; funktioniert auch problemlos. Jetzt kann ich das z.B. so implementieren:
Delphi-Quellcode:
Liegen die Daten in FDaten vor, kann ich Daten_Sortieren aufrufen. FDaten ist danach sortiert. Funktioniert, aber irgendwie ist mir dabei ein bisschen unwohl. Ich muss mir immer merken, ob und ab wo ich davon ausgehen kann, dass FDaten sortiert ist.
type
TDatenArray = array of TDaten; MeineKlasse = class(TObject) private FDaten: TDatenArray; procedure Daten_Sortieren; //Sortieralgorithmus ist hier ja unerheblich public property Daten: TDatenArray read FDaten; end; Wie kann ich das besser machen?
Irgendwie ist das eine grundsätzliche Frage für mich, die da mit rein spielt: Ein Objekt stellt die Prozeduren A und B bereit. A bearbeitet irgendwelche Daten (Felder) meines Objekts. B bearbeitet auch Felder und greift dabei auf die von A veränderten Felder zu. Wie regelt man das "schön"? Viele Grüße Ultimator |
AW: Feld sortieren und damit weiterarbeiten
Sieht so aus ob du eine property Sorted (also AutoSort) implementieren möchtest? Das hat allerdings Einfluß auf das Design der Klasse. Muß nach jedem OnChange der Daten ausgeführt werden. (Siehe z.B. TStringList). Z.B. deine property Daten geht dann so nicht mehr.
|
AW: Feld sortieren und damit weiterarbeiten
Danke Bjoerk!
Das bedeutet, ich müsste in der Klasse auch ein OnChange-Event meiner Daten zur Verfügung stellen und immer aufrufen, wenn ich etwas ändere? |
AW: Feld sortieren und damit weiterarbeiten
Das sollte die Klasse selbst übernehmen, wäre schicker? Ich schau mal nach wie TStringlist das macht und melde mich nochmal (Interessiert mich selber)..
|
AW: Feld sortieren und damit weiterarbeiten
Bei einer StringList oder jeder Liste mit einem einfachen Daten-Typ ist das kein Problem, denn eine Änderung der Daten erfolgt durch den Setter der Listen-Klasse.
Delphi-Quellcode:
Wird also der Setter aufgerufen, dann wird die Liste einfach neu sortiert.
TStringList = class...
property Strings[Index:Integer] read GetString write SetString; end; Arbeite ich aber mit Klassen als Items, dann müsste ich zum automatischen Sortieren von diesen Instanzen eine Rückmeldung haben, ob sich in denen etwas geändert hat, denn Inhaltsänderungen an der Klasse laufen über diese Klasse selber und nicht über die Listen-Klasse. |
AW: Feld sortieren und damit weiterarbeiten
Und natürlich wenn sich Count ändert. Am besten, man spielt es an einem konkreten Beispiel durch.
Ungetestet:
Delphi-Quellcode:
unit uSortedDaten;
interface uses Windows, SysUtils, Dialogs, Classes, Math; type TDatenItem = record Id: integer; Name: string; end; TDatenSortFlag = (dsfId, dsfName); TDaten = class private FItems: array of TDatenItem; FSorted: boolean; FSortFlag: TDatenSortFlag; FOnChange, FOnChanging: TNotifyEvent; function Get(Index: integer): TDatenItem; function GetCount: integer; procedure Put(Index: integer; const Value: TDatenItem); procedure SetCount(Value: integer); procedure SetSorted(const Value: boolean); procedure SortExchange(Index1, Index2: integer); function SortCompare(const A, B: TDatenItem): integer; procedure QuickSort(L, R: integer); procedure Changed; procedure Changing; public procedure Clear; procedure Add(const Value: TDatenItem); procedure Delete(Index: integer); procedure Insert(Index: integer; const Value: TDatenItem); procedure Exchange(Index1, Index2: integer); procedure Sort; function IndexOfID(Value: integer): integer; procedure Assign(Value: TDaten); procedure LoadFromFile(const FileName: string); procedure SaveToFile(const FileName: string); destructor Destroy; override; property Count: integer read GetCount; property Sorted: boolean read FSorted write SetSorted; property SortFlag: TDatenSortFlag read FSortFlag write FSortFlag; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; property Items[Index: integer]: TDatenItem read Get write Put; default; end; implementation type TFileStreamEx = class(TFileStream) private function ReadAnsiString: AnsiString; public function ReadInteger: integer; function ReadString: string; procedure WriteInteger(const Value: integer); procedure WriteString(const Value: string); end; { procedural } function Compare(const A, B: TDatenItem): boolean; begin Result := (A.Id = B.Id) and (A.Name = B.Name); end; { TDaten } destructor TDaten.Destroy; begin FOnChange := nil; FOnChanging := nil; Setlength(FItems, 0); end; procedure TDaten.Changed; begin if FSorted then Sort; if Assigned(FOnChange) then FOnChange(Self); end; procedure TDaten.Changing; begin if Assigned(FOnChanging) then FOnChanging(Self); end; procedure TDaten.Clear; begin if Count <> 0 then begin Changing; SetLength(FItems, 0); Changed; end; end; procedure TDaten.Add(const Value: TDatenItem); begin Insert(Count, Value); end; procedure TDaten.Delete(Index: integer); var I: integer; begin Changing; for I := Index to Count - 2 do FItems[I] := FItems[I + 1]; SetCount(Count - 1); Changed; end; procedure TDaten.Exchange(Index1, Index2: integer); var Temp: TDatenItem; begin Changing; Temp := FItems[Index1]; FItems[Index1] := FItems[Index2]; FItems[Index2] := Temp; Changed; end; function TDaten.Get(Index: integer): TDatenItem; begin Result := FItems[Index]; end; function TDaten.GetCount: integer; begin Result := Length(FItems) end; procedure TDaten.Insert(Index: integer; const Value: TDatenItem); var I: integer; begin Changing; SetCount(Count + 1); for I := Count - 1 downto Index + 1 do FItems[I] := FItems[I - 1]; FItems[Index] := Value; Changed; end; procedure TDaten.Put(Index: integer; const Value: TDatenItem); begin if not Compare(Value, FItems[Index]) then begin Changing; FItems[Index] := Value; Changed; end; end; procedure TDaten.SetCount(Value: integer); begin SetLength(FItems, Value); end; procedure TDaten.SortExchange(Index1, Index2: integer); var Temp: TDatenItem; begin Temp := FItems[Index1]; FItems[Index1] := FItems[Index2]; FItems[Index2] := Temp; end; function TDaten.SortCompare(const A, B: TDatenItem): integer; begin if FSortFlag = dsfName then Result := AnsiCompareText(A.Name, B.Name) else Result := CompareValue(A.Id, B.Id); end; procedure TDaten.QuickSort(L, R: integer); var I, J, K: integer; Pivot: TDatenItem; begin repeat I := L; J := R; K := (L + R) shr 1; Pivot := FItems[K]; repeat while SortCompare(FItems[I], Pivot) < 0 do Inc(I); while SortCompare(FItems[J], Pivot) > 0 do Dec(J); if I <= J then begin SortExchange(I, J); Inc(I); Dec(J); end; until I > J; if L < J then QuickSort(L, J); L := I; until I >= R; end; procedure TDaten.Sort; begin if Count > 1 then QuickSort(0, Count - 1); end; procedure TDaten.SetSorted(const Value: boolean); begin if FSorted <> Value then begin Changing; FSorted := Value; Changed; end; end; function TDaten.IndexOfID(Value: integer): integer; var I: integer; begin Result := -1; for I := 0 to Count - 1 do if FItems[I].Id = Value then begin Result := I; Break; end; end; procedure TDaten.Assign(Value: TDaten); var I: integer; begin Clear; for I := 0 to Value.Count - 1 do Add(Value[I]); end; procedure TDaten.LoadFromFile(const FileName: string); var Stream: TFileStreamEx; I, N: integer; Value: TDatenItem; begin if FileExists(FileName) then begin Clear; Stream := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone); try N := Stream.ReadInteger; for I := 0 to N - 1 do begin Value.Id := Stream.ReadInteger; Value.Name := Stream.ReadString; Add(Value); end; finally Stream.Free; end; end; end; procedure TDaten.SaveToFile(const FileName: string); var Stream: TFileStreamEx; I: integer; begin Stream := TFileStreamEx.Create(FileName, fmCreate); try Stream.WriteInteger(Count); for I := 0 to Count - 1 do begin Stream.WriteInteger(FItems[I].Id); Stream.WriteString(FItems[I].Name); end; finally Stream.Free; end; end; { TFileStreamEx } function TFileStreamEx.ReadInteger: integer; begin ReadBuffer(Result, SizeOf(integer)); end; function TFileStreamEx.ReadAnsiString: AnsiString; var N: integer; begin N := ReadInteger; SetLength(Result, N); if N > 0 then ReadBuffer(Result[1], N); end; function TFileStreamEx.ReadString: string; // need AnsiStringBuffer begin Result := ReadAnsiString; end; procedure TFileStreamEx.WriteInteger(const Value: integer); begin WriteBuffer(Value, SizeOf(integer)); end; procedure TFileStreamEx.WriteString(const Value: string); var N: integer; begin N := Length(Value) * SizeOf(Char); WriteInteger(N); if N > 0 then WriteBuffer(Value[1], N); end; end. |
AW: Feld sortieren und damit weiterarbeiten
Hallo zusammen,
Danke an alle! Ein bisschen aufwendiger ist es ja schon, als mir zu merken, wann ich die Daten sortiert hab :stupid: Ich werde mal in mich gehen - das Prinzip hab ich verstanden, jetzt muss ich mal schauen, wie ich's umsetze. |
AW: Feld sortieren und damit weiterarbeiten
Ja, ist ziemlich aufwendig. Am besten wäre es vielleicht, das Sort aus der Changed
herauszunehmen und vom Event erledigen zu lassen. Man könnte noch einen Setter SetSortFlag (ala SetSorted) einführen und im destructor hab ich das das inherited vergessen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:40 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 by Thomas Breitkreuz