![]() |
Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Ich habe eine Klasse TAudioFile mit verschiedenen Eigenschaften, z.B. Artist, Titel, Album etc. (für diese Problemstellung hier alles nur Strings).
Jetzt stellt sich mir das Problem, dass ich eine Liste von solchen Objekten sortieren möchte, und zwar nicht nur nach einem Sortierkriterium, sondern nach mehreren, die der User zur Laufzeit festlegen kann. Also z.B. primäres Sortierkriterium: Artist. Bei Gleichheit: Sortierung nach Album, anschließend Sortierung nach Titel. Wenn ich 10 Eigenschaften habe, müsste ich also 10*9 = 90 Compare-Funktionen für die Sort-Routine schreiben :shock:, wenn ich zwei "Stufen" zulasse. Bei 3 Stufen (wie im Beispiel) 10*9*8 = 720.... :pale: Im DF ist die ![]() Ist sicherlich ne schöne Sache, nur würde diese Lösung bedeuten, dass ich in einem recht umfangreichen Projekt alle ".Artist", ".Album" etc. durch ein ".EigenschaftenArray[CONST_ARTIST]" etc. ersetzen müsste (mit entsprechenden Konstanten CONST_ARTIST). Ein zusätzlicher großer Nachteil wäre auch, dass man Dinge wie Autovervollständigung in der IDE zum schnelleren Finden der richtigen Eigenschaftsbezeichnung vergessen kann - der Code verliert an Übersichtlichkeit und Wartbarkeit. Ich suche also eine Möglichkeit, wie ich die bisherige Struktur beibehalten kann, und sie um ein Array zu erweitern, sodass aber in den einzelnen Zellen des Arrays dieselben Infos stecken wie in den einzelnen Eigenschaften. Also so, dass ich
Delphi-Quellcode:
im Code völlig synonym zu
MyAudioFile.Artist
Delphi-Quellcode:
verwenden kann. Dabei muss als Index auch eine Variable entsprechenden Wertes möglich sein - z.B.:
MyAudioFile.EigenschaftenArray[CONST_ARTIST]
Delphi-Quellcode:
Eine simple Ersetzung vor dem Kompilieren ist also nicht möglich.
MyAudioFile.EigenschaftenArray[SortierPrioritätenArray[1]]
|
Re: Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Dazu bietet Delphi die Möglichkeit der Indizierung von Eigenschaften.
Beispiel:
Delphi-Quellcode:
Dann kannst du intern auf ein Array zugreifen.
type
TMyClassStringIndex = (siName, siAlbum, siTitel); TMyClass = class(TObject) private FStrings: array [TMyClassStringIndex] of string; function GetString(Index: TMyClassStringIndex): string; procedure SetString(Index: TMyClassStringIndex; const Value: string); protected property Strings[Index: TMyClassStringIndex] read GetString write SetString; public property Name: string Index siName read GetString write SetString; property Album: string Index siAlbum read GetString write SetString; // usw... end; |
Re: Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Delphi-Quellcode:
falls er da meckert musst du dir halt getter und setter bauen.
property Artist: string read Props[cARTIST] write Props[cARTIST];
Delphi-Quellcode:
//Ja, genau so.... :roll:
public
procedure SetArtist(value: string); function GetArtist: string; published property Artist: string read GetArtist write SetArtist; |
Re: Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Hi,
warum genau verwirfst du denn die Idee mit dem mehrfachen Sortieren? Ich denke die ist gar nicht so der schlechte Ansatz. Du brauchst natürlich weiterhin verschiedene Compare-Methoden (je nach Datentyp), aber für dieses Beispiel wolltest du dich ja auf Strings einschränken. Also wenn du eine Liste von Objekten nach dem ersten Kriterium sortierst, schaffst du dies in O(n*log(n)) (im Mittel falls du Quicksort verwendest). Gehst du diese Liste durch, benötigst du dafür O(n) Zeit, was durch das Sortieren dominiert wird. Suchst du nun hier die Gruppen, die gleich sind und sortierst diese erneut, hättest du maximal O(n*log(n)). Wenn du also nach der Effizienz gehst, ist mehrfaches Sortieren assymptotisch nicht Rechenzeitaufwändiger als einfaches Sortieren. Allerdings kannst du hier noch einiges verbessern. Eine einfache Möglichkeit ist es, dass du Elemente, die den gleichen Wert (nach dem aktuellen Suchkriterium) besitzen in ein Array packst. Genau genommen kannst du sogar in-place arbeiten. Du hast dein zu sortierendes Array und speicherst einfach den Index der Teilfelder die nach dem aktuellen Kriterium gleiche Elemente enthalten. Nun ist dein Feld bis auf diese Elemente schon sortiert. Das heißt, du brauchst nach dem nächsten Suchkriterium nur noch diese Felder sortieren. Dies sollte im Mittel deutlich schneller gehen. Einerseits fallen in jeder Iteration weitere Objekte raus, die schon sortiert sind und andererseit entstehen (wahrscheinlich) kleine Partionen, diese lassen sich dann deutlich schneller sortieren. Zudem brauchst du weiterhin nur paarweise zu vergleichen. Am meisten dürftest du allerdings davon profitieren, wenn du gleich sortiert einfügst. Wenn du ein Objekt bekommst, könntest du jede seiner Eigenschaften in je eine Liste (die dann konsistent gehalten werden müsste) sortiert einfügen. Sollte es dann zu einer Abfrage kommen, Liegt die Sortierung nach dem Kriterium schon vor. Bei einfügen sollte es in der Regel wenig Zeit kosten (sehen wir mal vom ersten hinzufügen eines Archivs ab), danach kommen doch eher geringe Mengen hinzu. Jeder Eintrag in einer solchen Liste kann dann noch einen Verweis auf das eigentliche Objekt enthalten (also ein Tupel aus dieser einen Eigenschaft nach der die Liste sortiert ist + Verweis auf das eigentliche Objekt). Die ist allerdings ohne Frage keine speicher schonende Variante, da die Verweise sehr redundant abgelegt werden. Es muss aber eine solche Liste auch nicht für jedes Kriterium angelegt werden. Sicherlich macht es für Dinge, nach denen eher selten sortiert wird, bzw. die mit hoher Wahrscheinlichkeit gleich sind (z.B. SampleRate, Stimmung, ...) weniger Sinn eine solche Liste zu verwalten. Sollten diese Kriterien verwendet werden, muss halt vorher klassisch sortiert werden. Nun alles zusammen: Beim einfügen von neuen Daten, die wichtigen Eigenschaften sortiert ablegen (mit einem Verweis auf dieses neue Datum). Wird nach mehreren Kriterien sortiert, so wird das Array zuerst nach dem primären Kriterium sortiert (sollte es eine Eigenschaft sein, zu der schon eine Sortierte Liste gehört, braucht man hier nichts zu tun und kann diese abrufen). In dieser Sortierung alle gleichen Elemente jeweils analog nach dem zweiten Kriterium sortieren (bis alles sortiert oder keine weiteren Kriterien vorhanden). Gruß Der Unwissende |
Re: Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Es ist ja nicht das sortieren alleine. Dazu verwende ich auch die mitgelieferte Sort-Funktion der TObjectlist, wodurch sich das Sortieren auf kleine Mini-Funktionen (eben die Compare-Funktionen) beschränkt. Wenn ich den Code jetzt dahingehend erweitere, und Teile neu sortiere, ist das viel Coding-Aufwand.
Hinzu kommt, dass ich für die entsprechend sortierten Listen auch jeweils eine Binärsuche nach der sortierten Eigenschaft programmiert habe, und bei einem Treffer z.B. alle Objekte ausgebe, die die primäre Eigenschaft besitzen, oder aber die primäre UND sekundäre - da käme dann auch entsprechend Aufwand auf mich zu. Ich brauche dieses variable Verfahren für folgendes:
Das Stichwort, was ich benötigte, war Getter/Setter :wall:. Ich hätte natürlich zuerst für jede Eigenschaft nen eigenen Setter/Getter geschrieben, aber wenn das auch in einem geht, ist das natürlich ne feine Sache :D Ist doch richtig, dass die Getter-Methode einfach den Index-ten String aus dem Array zurückliefert, und der Setter einfach den String im Array neu setzt, oder? Also einfach
Delphi-Quellcode:
Jetzt muss ich zwar die Klasse etwas umbauen (das sind bis jetzt alles einfach nur Variablen, keine Propertys), aber der Rest des Projektes kann so bleiben.
function GetString(Index: TMyClassStringIndex): String;
begin result := FStrings[Index]; end; procedure SetString(Index: TMyClassStringIndex; const Value: string); begin FStrings[Index] := Value; end; |
Re: Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Zitat:
|
Re: Synonyme Bezeichnungen für eine Objekt-Eigenschaft
Danke nochmal dafür. Bin jetzt endlich dazu gekommen, das auch tatsächlich zu implementieren, und es läuft wunderbar. Nur eine Kleinigkeit für die Nachwelt:
Statt
Delphi-Quellcode:
muss es natürlich heißen
property Strings[Index: TMyClassStringIndex] read GetString write SetString;
Delphi-Quellcode:
property Strings[Index: TMyClassStringIndex]: String read GetString write SetString;
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:14 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