AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Sortierte TObjectList - Einträge richtig einfügen
Thema durchsuchen
Ansicht
Themen-Optionen

Sortierte TObjectList - Einträge richtig einfügen

Ein Thema von Benmik · begonnen am 17. Jul 2015 · letzter Beitrag vom 24. Sep 2015
Antwort Antwort
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.052 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#1

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 21. Sep 2015, 19:05
Wenn ich TComparer<*>.Default.Compare an Stellen sehe, wo nur nen String oder Integer verglichen wird, bekomm ich das kalte Grausen.
Und am Ende wird wieder gemeckert, dass der Code langsam wird.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.079 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 22. Sep 2015, 09:10
Wenn ich TComparer<*>.Default.Compare an Stellen sehe, wo nur nen String oder Integer verglichen wird, bekomm ich das kalte Grausen.
Und am Ende wird wieder gemeckert, dass der Code langsam wird.
Wie wäre es richtig(er)?
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#3

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 22. Sep 2015, 21:27
Möglicherweise
Delphi-Quellcode:
class function TLogFile.IdentityCompare( const L, R: TLogFile ): Integer;
begin
  Result := L.FFileId - R.FFileId;
end;
zum Beispiel ?
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 22. Sep 2015, 22:45
Oder mit einer von diesen Routinen
http://docwiki.embarcadero.com/RADSt...leichsroutinen
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#5

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 24. Sep 2015, 12:10
Da ich doch eine ganze Weile gebraucht habe, um mir einen zufriedenstellenden Code mit diversen Funktionalitäten zusammenzubasteln, stelle ich hier mal für alle Google-Ankömmlinge das Gerüst des Codes ein. Ich bin immer sehr dankbar für solche fertigen Codeteile bei Themen, bei denen ich Neuland betrete (hat ja auch schon unsere Kanzlerin bemerkt...).
Folgende zusätzliche Funktionalitäten habe ich benötigt und daher eingebaut:
- Ist ein gesuchter Wert mehrfach in der Liste vorhanden, gehe zum ersten
- Speichere und lade die Werte in einer / aus einer Datei
- Verschlüssele die Datei, falls gewünscht
- Stelle vor einer binären Suche sicher, dass die Liste (richtig) sortiert ist
Nochmal: Es handelt sich um ein Gerüst! Für Verbesserungen bin ich natürlich dankbar.
Ach, und noch was: Natürlich weiß ich, dass der Code style sowas von pfui ist. Seit ich aber mitbekommen habe, dass der allwissende Zuchtmeister David Heffernan (stackoverflow) ebenfalls nicht im Traum daran denkt, sich an die von oben aufoktroyierten Regeln zu halten, bin ich da doch freier geworden.
Delphi-Quellcode:
uses Classes,Generics.Defaults,Generics.Collections,SysUtils,Dialogs,Math,
     SynCrypto; // Synopse framework. Copyright (C) 2012 Arnaud Bouchez, http://synopse.info

type
  TSortArt = (soNone,soByString,soByInteger);

type
  TQuelle = class(TObject)
    ValString : String;
    ValInt : Integer;

  end;

  TQuellListe = class(TObjectList<TQuelle>)
  private
    FSortierung : TSortArt;
    function CompInteger(const L,R: TQuelle) : Integer;
    function CompString(const L,R: TQuelle) : Integer;
  public
    constructor Create(OwnsObjects:Boolean = True);
    procedure Sort(SortArt:TSortArt);
    function FindString(const Str:string;var P:Integer):Boolean;
    function FindInt(const I:integer;var P:Integer):Boolean;
    function AddSortedStr(const Ziel:TQuelle):Boolean;
    procedure SaveToFile(Dateiname:string;PW:string = '');
    procedure ReadFromFile(Dateiname:string;PW:string = '');
  end;


implementation

constructor TQuellListe.Create(OwnsObjects:Boolean = True);
begin
  inherited Create(TComparer<TQuelle>.Construct(CompString),OwnsObjects);
  FSortierung := soNone;
end;

function TQuellListe.CompInteger(const L, R: TQuelle): Integer;
begin
  Result := TComparer<integer>.Default.Compare(L.ValInt,R.ValInt);
  // Schneller: Result := L.ValInt - R.ValInt;
end;

function TQuellListe.CompString(const L, R: TQuelle): Integer;
begin
  Result := TComparer<string>.Default.Compare(L.ValString,R.ValString);
  // Oder: System.SysUtils.AnsiCompareStr, System.SysUtils.AnsiCompareText, ...
end;

procedure TQuellListe.Sort(SortArt: TSortArt);
begin
  If Assigned(Self) and (Self.Count > 0) then begin
    Case SortArt of
      soByString : inherited Sort(TComparer<TQuelle>.Construct(Self.CompString));
      soByInteger : inherited Sort(TComparer<TQuelle>.Construct(Self.CompInteger));
    end;
    FSortierung := SortArt;
  end;
end;

function TQuellListe.FindString(const Str: string; var P: Integer): Boolean;
var L:TQuelle;
begin
  Result := (FSortierung = soByString);
  p := -1;
  If not Result then begin
    Showmessage('Liste ist nicht oder falsch sortiert! '); // Nur zum Testen
  end else begin
    Result := Assigned(Self) and (Self.Count > 0);
    If Result then begin
      L := TQuelle.Create;
      L.ValString := Str;
      try
        Result := BinarySearch(L, p,
          TComparer<TQuelle>.Construct(function (const L, R: TQuelle): Integer begin Result := AnsiCompareText(L.ValString,R.ValString); end));
        While Result and (p > 0) and (Self[p - 1].ValString = Str) do // falls Str mehrfach vorhanden - in case of more than one occurence of Str
          Dec(p);
      Finally
        L.Free;
      end;
    end;
  end;
end;

function TQuellListe.FindInt(const I: integer; var P: Integer): Boolean;
var L:TQuelle;
begin
  Result := (FSortierung = soByInteger);
  p := -1;
  If not Result then begin
    Showmessage('Liste ist nicht oder falsch sortiert! '); // Nur zum Testen
  end else begin
    Result := Assigned(Self) and (Self.Count > 0);
    If Result then begin
      L := TQuelle.Create;
      L.ValInt := I;
      try
        Result := BinarySearch(L, p,
        TComparer<TQuelle>.Construct(function (const L, R: TQuelle): Integer begin Result := CompareValue(L.ValInt,R.ValInt); end));
        While Result and (p > 0) and (Self[p - 1].ValInt = I) do
          Dec(p);
       Finally
         L.Free;
      end;
    end;
  end;
end;

procedure TQuellListe.ReadFromFile(Dateiname: string;PW:string = '');
var Reader: TReader; Stream,VStream:TMemoryStream; Ziel:TQuelle; Digest: TSHA256Digest;
begin
  Stream := TMemoryStream.Create;
  If PW <> 'then begin
    VStream := TMemoryStream.Create;
    VStream.LoadFromFile(Dateiname);
    SHA256Weak(PW, Digest);
    VStream.Position := 0;
    SynCrypto.AESFull(Digest, 256, VStream.Memory, VStream.Size, Stream, False);
  end else begin
    Stream.LoadFromFile(Dateiname);
  end;
  Stream.Position := 0;
  Reader := TReader.Create(Stream, 4096);
  Try
    Self.Clear;
    Reader.ReadListBegin;
    While not Reader.EndOfList do begin
      Ziel := TQuelle.Create;
      Ziel.ValInt := Reader.ReadInteger;
      Ziel.ValString := Reader.ReadString;

      Self.Add(Ziel);
    end;
    Reader.ReadListEnd;
  Except
    Showmessage(IntToStr(Self.Count)); // Nur zum Testen
    Reader.Free;
    Stream.Free;
    exit;
  End;
  Reader.Free;
  Stream.Free;
end;

procedure TQuellListe.SaveToFile(Dateiname:string;PW:string = '');
var Writer: TWriter; Stream,VStream:TMemoryStream; i:integer; Digest: TSHA256Digest;
begin
  Stream := TMemoryStream.Create;
  Writer:= TWriter.Create(Stream, 4096);
  Try
    Writer.WriteListBegin;
    For i := 0 to Self.Count - 1 do begin
      Writer.WriteInteger(Self[i].ValInt);
      Writer.WriteString(Self[i].ValString);
    end;
    Writer.WriteListEnd;
    Writer.FlushBuffer;
    If PW <> 'then begin
      VStream := TMemoryStream.Create;
      SHA256Weak(PW, Digest);
      Stream.Position := 0;
      SynCrypto.AESFull(Digest, 256, Stream.Memory, Stream.Size, VStream, True);
      VStream.SaveToFile(Dateiname);
      VStream.Free;
    end else begin
      Stream.SaveToFile(Dateiname);
    end;
  Except
    Writer.Free;
    Stream.Free;
  End;
  Writer.Free;
  Stream.Free;
end;

function TQuellListe.AddSortedStr(const Ziel: TQuelle): Boolean;
var P: Integer;
begin
  Result := Assigned(Ziel) and (Ziel.ValString <> '') and (FSortierung = soByString);
  If Result then begin
    FindString(Ziel.ValString,p);
    Result := (p > -1);
    If Result
      then Self.Insert(p,Ziel);
  end else if FSortierung <> soByString then begin
    Showmessage('Liste ist nicht oder falsch sortiert! '); // Nur zum Testen
  end;
end;

Geändert von Benmik (24. Sep 2015 um 18:07 Uhr) Grund: David Heffernan
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.052 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#6

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 24. Sep 2015, 16:39
Nur eine Anregung: Das Laden und Speichern nicht in die Listenklasse direkt implementieren - ja ich weiß, das ist so toll, direkt nen list.ReadFromFile zu machen.
Warum? Trennung von Zuständigkeiten - das eine ist eine Liste, die kümmert sich um das Verwalten von Objekten und das andere ist ein Speicher/Lade Mechanismus (zzgl Encryption).

Kann man alleine an den Uses schon sehen - eine Encryption Unit in einer Listenklasse Unit. Kann dir aus eigener Erfahrung berichten, dass sowas schnell ungeahnte Ausmaße annimmt.

Willst nur kurz ne kleine Anwendung schreiben, brauchst ne Liste und bumm ziehst dir dein halbes Code Repo mit rein, weil die alle miteinander verdrahtet sind (und am Ende am besten noch ne Abhängigkeit auf eine DLL, weil in irgendeiner Unit Funktionen daraus statisch importiert werden - alles schon gehabt)
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#7

AW: Sortierte TObjectList - Einträge richtig einfügen

  Alt 24. Sep 2015, 16:51
Eine Überlegung dazu: Ich vermute mal, dass TList und TObjectlist deswegen keine ReadFromFile/SaveToFile haben, weil keine Informationen über die Objekte vorliegen. Bei TStringList, wo dies bekannt ist, gibt es diese Funktionen, und TStringList ist ja auch nichts anderes als eine spezialisierte TList. Wenn man eine Liste mit selbst typisierten Objekten hat, dann finde ich es passend, auch die spezialisierte Routine in die Klasse zu geben.

Aber eigentlich ging es mir nur darum zu zeigen, wie es geht, denn die Kombination von TObjectlist, Stream, TWriter/TReader und dann auch noch Verschlüsselung war Neuland für mich. Das Cryptomodul war dabei echt nur eine Zugabe, aber doch eine nützliche, finde ich.
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:34 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