Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Sortierfunktion nach Datum in einer TStringList (https://www.delphipraxis.net/185745-sortierfunktion-nach-datum-einer-tstringlist.html)

juergen 3. Jul 2015 18:08

Sortierfunktion nach Datum in einer TStringList
 
Hallo zusammen,

ich hatte bisher beim Einlesen von Dateien in eine StringList das Datum der jeweiligen Datei als Integerwert in das jeweilige Object der StringList gespeichert und konnte die StringList somit gut nach Datum sortieren. Wenn Dateien das gleiche Datum hatten, wurde dann nach Dateiname sortiert
Delphi-Quellcode:
  function DoCompareByDate(List: TStringList; Index1, Index2: Integer): Integer;
  begin
    Result := 0;
    if Assigned(List) then begin
      if (Integer(List.Objects[Index1]) < Integer(List.Objects[Index2])) then begin
        Result := 1;
      end
      else if (Integer(List.Objects[Index1]) > Integer(List.Objects[Index2])) then begin
        Result := -1;
      end;
    end;
  end;

Nun kann ich das Datum nicht mehr als Object in der StringList speichern, da was anderes dafür vorgesehen ist.
Meine derzeitiges Konzept:
Damit ich weiterhin auch nach Datum sortieren kann, würde ich beim Einlesen der Dateien eine *zweite, neue* Stringlist füllen, welche dieselbe Object-ID erhält wie die "Master"-StringList. In der zweiten Stringlist würde ich dann nur das Datum speichern.
Meine Datumssortierfunktion könnte dann auf diese 2. Liste angewendet werden.

Meine Fragen:
- Wie bekomme ich die "Master" Stringlist so sortiert wie die Datums-StringList (beide Object-Ids sind ja gleich)?
- Gibt es evtl. alternative Konzept-Vorschläge?

Edit: Eine Umstellung der vorhandenen Master-TStringList auf z.B. TObjectList würde ich nur sehr, sehr ungern vornehmen...


Vielen Dank schon mal im Voraus!

DeddyH 3. Jul 2015 18:39

AW: Sortierfunktion nach Datum in einer TStringList
 
Wieso erstellst Du nicht eine Klasse, die alle benötigten Daten enthält, und hinterlegst diese dann in der Objects-Eigenschaft? Dafür ist diese ja auch eigentlich vorgesehen, Du musst nur daran denken, diese beim Löschen eines Eintrags auch wieder freizugeben bzw. freigeben zu lassen.

Dalai 3. Jul 2015 19:03

AW: Sortierfunktion nach Datum in einer TStringList
 
Alternativ kann man auch eine neue von TStringList abgeleitete Klasse erstellen, die die nötigen Attribute enthält, und diese statt der TStringList nutzen.

MfG Dalai

juergen 3. Jul 2015 20:01

AW: Sortierung einer "Master"-TStringList nach der Reihenfolge einer 2. TStringList
 
Hallo,

danke für die Antworten. In einem neuen Projekt würde ich in diesem Fall mit Objekten arbeiten, auch wenn ich mich momentan damit noch nicht so auskenne.
Da aber schon viele Anpassungen meiner jetzigen TStringList-Methoden erfolgt sind (z.B. sichern der Zahl (Datum) aus dem Object über die SaveToFile- oder SaveToStream-Methoden, LoadFromFile, usw.), möchte ich für dieses Projekt keine so großen Änderungen mehr vornehmen.

Was mir jetzt nur noch fehlt ist die Sortierung meiner "Master"-TStringList nach der zweiten Datums-TStringList.
In beiden Listen sind in den Objecten die gleichen eindeutigen Zahlen gespeichert. Das heißt, beim befüllen der beiden TStringListen werden die jeweiligen Objecte mit den gleichen eindeutigen Nummern versehen.
Z. B. enthalten beide Listen im 4. Item die Object-Nr 8815468541, im 5. Item die Object-Nr 8815468542 usw.

Nun sortiere ich die zweite TStringList nach Datum, welches in den Items hinterrlegt ist.
Wie bekomme ich nun die Master-StringList so sortiert, dass diese dieselbe Reihenfolge hat wie die zweite TSringList? (Reihenfolge = die in dem Object hinterlegte Nummer)
Ich hoffe ich konnte mich verständlich ausdrücken was die Sortieranforderung betrifft.

Edit: Titel geändert.

idefix2 3. Jul 2015 20:31

AW: Sortierfunktion nach Datum in einer TStringList
 
Egal wie du es machst, es wird extrem ineffizient werden, weil du in einer Stringlist nach einem bestimmten Wert in Objects nur sequentiell suchen kannst.
Wenn du nur zum Sortieren in eine extra Stringlist in Items das Datum schreibst und in Objects alle zu diesem Datum gehörenden Daten, dann kannst du, wenn im restlichen Programm eine Änderung der Datenstruktur zu kompliziert ist, nach dem Sortieren die Daten wieder in deine zwei Stringlisten aufteilen, bzw. ausgehend von deiner nach Datum sortierten Stringlist die zweite Stringliste neu erstellen.

DeddyH 3. Jul 2015 21:17

AW: Sortierfunktion nach Datum in einer TStringList
 
Ich (und vermutlich auch ein paar andere User) habe ein Problem damit, zusammengehörige Daten in unterschiedlichen Listen zu hinterlegen, das ist extrem fehleranfällig, vor allem dann, wenn aus welchen Gründen auch immer die Listen unterschiedlich viele Einträge enthalten, da sind AVs einfach vorprogrammiert. Von daher würde ich eher zur TObjectList tendieren, die kannst Du nach eigenem Gusto (um)sortieren, und eine Methode zur Ausgabe ist ja auch schnell geschrieben. Das mag zwar im Moment etwas Aufwand sein, aber erstens ist der überschaubar und zweitens zahlt sich das langfristig aus.

juergen 3. Jul 2015 21:20

AW: Sortierfunktion nach Datum in einer TStringList
 
Danke an alle beteiligten! :dp:

Wie ich jetzt gemerkt habe, kann ich machen was ich will, ich habe immer irgendein Problem, solange ich nicht die Struktur ändere.
Ich schreibe nun wie ursprünglich erst einmal das Datum als Integer wieder in das jeweilige Object des Item. Die andere Erweiterung muss warten.
Dieser Thread ist somit gelöst!

Sir Rufo 4. Jul 2015 00:42

AW: Sortierfunktion nach Datum in einer TStringList
 
Das ist eigentlich alles was du brauchst:
Delphi-Quellcode:
unit MyObjectList;

interface

uses
  {System.}Classes,
  {System.}Generics.Collections,
  {System.}SysUtils;

type
  TMyObjectList<T: class> = class( TObjectList<T> )
  public
    procedure ToStrings( AStrings: TStrings; IncludeObjects: Boolean = false ); overload;
    procedure ToStrings( AStrings: TStrings; AConverter: TFunc<T, string>; IncludeObjects: Boolean = false ); overload;
  end;

implementation

{ TMyObjectList<T> }

procedure TMyObjectList<T>.ToStrings( AStrings: TStrings; IncludeObjects: Boolean );
begin
  ToStrings( AStrings,
    function( AItem: T ): string
    begin
      Result := AItem.ToString( );
    end, IncludeObjects );
end;

procedure TMyObjectList<T>.ToStrings( AStrings: TStrings; AConverter: TFunc<T, string>; IncludeObjects: Boolean );
var
  LItem: T;
begin
  AStrings.BeginUpdate;
  try
    AStrings.Clear;
    for LItem in Self do
    begin
      if IncludeObjects then
        AStrings.AddObject( AConverter( LItem ), LItem )
      else
        AStrings.Add( AConverter( LItem ) );
    end;
  finally
    AStrings.EndUpdate;
  end;
end;

end.
Da sammelst du alle Instanzen, sortierst diese, wie gewünscht und lässt dir mit den beiden Methoden die StringListen befüllen:
Delphi-Quellcode:
FFileInfos : TMyObjectList<TFileInfo>;

FFileInfos.Sort( {Sortier-Methode} ); // Sortierung für ListBox
FFileInfos.ToStrings( 
  ListBox1.Items,
  True );

FFileInfos.Sort( {Sortier-Methode} ); // Sortierung für ComboBox
FFileInfos.ToStrings( 
  ComboBox1.Items,
  function ( Item: TFileInfo ) : string
  begin
    Result := Format('%s (%d)',[Item.Name,Item.Size]);
  end,
  True );

Hansa 4. Jul 2015 12:40

AW: Sortierfunktion nach Datum in einer TStringList
 
Wie DeddyH würde ich auch raten, keine 2 Stringlisten zu benutzen. Die irgendwie zu synchronisieren ist echt zu fehlerträchtig, weil dann zwie Datenquellen vorhanden sind. Vor allem ist das aber auch unnötig. Deddy hat sa vielleicht zu knapp beschrieben.

Ich denke er meint (ungefähr zumindest) das, was ich jetzt etwas ausführlicher schreibe. Der Vorteil einer TObjectList ist ja der, dass man in die einzelnen Objekte dieser Liste so ziemlich alle Datentypen die es gibt, reinpacken kann. Definiere dir also einen Typ, der zumindest alles enthält, was angezeigt werden soll. Da geht natürlich auch noch mehr. Diese TObjectList füllst du dann mit deinen Daten.

Jetzt kommt das Stringgrid. Dieses wird gefüllt aus der TObjectList. Soll dieses jetzt sortiert werden, dann sortierst du die TObjectList, machst das Stringgrid leer und befüllst es wieder aus der sortierten TObjectList. Das wars dann. Wegen der TObjectList : das ist zwar Allzweckwaffe, aber man muss diese auch richtig benutzen. Beim Delphi-Treff gibts ein gutes Tutorial dazu.

Popov 4. Jul 2015 13:35

AW: Sortierfunktion nach Datum in einer TStringList
 
@juergen

Also die Idee von DeddyH ist wohl die Beste. Wenn Objekt bereits belegt ist, dann eine Klasse schreiben die sowohl dieses Objekt enthält wie auch ein Zweites. Letztendlich die einfachste Methode.

Trotzdem, hier mal eine "Trick 17" Methode. Liste (TStringList) enthält 1000 Daten mit Uhrzeiten. Dennoch wird sie korrekt alphabetisch sortiert. Der eigentliche Trick ist, dass die Daten anders gespeichert sind als sie angezeigt werden:

Delphi-Quellcode:
function DateTimeFormatDE: TFormatSettings;
begin
  Result.DateSeparator := '.';
  Result.TimeSeparator := ':';
  Result.ShortDateFormat := 'dd/MM/yyyy hh:nn:ss';
end;

function DateTimeFormatINT: TFormatSettings;
begin
  Result.DateSeparator := '-';
  Result.TimeSeparator := ':';
  Result.ShortDateFormat := 'yyyy/MM/dd hh:nn:ss';
end;

procedure ListeMitZufaelligenDatenGenerieren(List: TStrings; Max: Integer);
var
  i: Integer;
  dt: TDateTime;
begin
  for i := 1 to Max do
  begin
    dt := EncodeDateTime(Random(115) + 1900, Random(12) + 1, Random(28) + 1,
      Random(24), Random(60), Random(60), Random(1000));
    List.Add(DateTimeToStr(dt, DateTimeFormatDE)); //erstelle deutsch-typsch
  end;
end;

procedure DatenInListeInAnderesFormatAendern(List: TStrings);
var
  i: Integer;
  dt: TDateTime;
begin
  for i := 0 to List.Count - 1 do
  begin
    dt := StrToDateTime(List[i], DateTimeFormatDE); //lese deutsch-typsch
    List[i] := DateTimeToStr(dt, DateTimeFormatINT); //verändere international
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //Datum deutsch-typisch 27.03.2015 14:58:36. Für Sortierung ungeeigent
  ListeMitZufaelligenDatenGenerieren(ListBox1.Items, 1000);

  //Datum untypisch 2015-03-27 14:58:36. Für Sortierung geeignet
  DatenInListeInAnderesFormatAendern(ListBox1.Items);

  ListBox1.Sorted := True;

  ListBox1.Style := lbOwnerDrawFixed;
end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  Delta: Integer;
  dt: TDateTime;
  s: String;
begin
  with (Control as TListbox) do
  begin
    //Das Datum ist in der StringList untypisch gespeichert: 2015-03-27 14:58:36
    //Hier wird es für die typische Darstellung 27.03.2015 14:58:36 verändert.

    dt := StrToDateTime(Items[Index], DateTimeFormatINT); //lese international
    s := DateTimeToStr(dt, DateTimeFormatDE); //erstelle deutsch-typsch

    Delta := (ItemHeight div 2) - (Canvas.TextHeight(Items[Index]) div 2);
    Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top + Delta, s);
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:27 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz