Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Sortierte TObjectList - Einträge richtig einfügen (https://www.delphipraxis.net/185916-sortierte-tobjectlist-eintraege-richtig-einfuegen.html)

Benmik 17. Jul 2015 12:48

Sortierte TObjectList - Einträge richtig einfügen
 
Ich habe eine sortierte TObjectList in einer eigenen Klasse. Ich muss nun feststellen, ob ein bestimmtes Element bereits in der Liste vorhanden ist und - wenn nicht - es an der richtigen Stelle einfügen.

Ich habe mir dazu eine quasi aufgebohrte Version von IndexOf mit einer binären Suche gebastelt, die mir bei Nichtfinden in p die richtige Einfügeposition zurückmeldet:
Delphi-Quellcode:
type
  TZiel = class(TObject)
    WERT1     : Word;
    WERT2     : Word;
    WERT3     : String;
    WERT4     : String;
    WERT5     : Cardinal;
    WERT6     : Int64;
    WERT7     : Int64;
  end;
  TZielListe = class(TObjectList)

function TZielListe.WertGefunden(Wert:string;var WertPos:Integer):Boolean;
var p, Anz, MWert: Integer;
begin
  // WertPos ist entweder die Position des gefundenen Wertes oder die Einfügeposition in die sortierte Liste, falls nicht gefunden
  WertPos := 0;
  If Self.Count = 0 then
    exit(False);
  p  := 0;
  Anz := Self.Count;
  while p < Anz do
    begin
    MWert := p + (Anz - p) div 2;
    if Self[MWert].Wert3 = Wert then
    begin
      WertPos := MWert;
      Exit(True);
    end;
    if AnsiCompareText(Wert,Self[MWert].Wert3) = -1 then
       Anz := MWert
     else
       p  := MWert + 1;
  end;
  If (p = Anz) or (AnsiCompareText(Wert,Self[p].Wert3) > 0) then
    WertPos := p
  else
    WertPos := Max(0,p - 1);
  Result := False;
end;
Jetzt hätte ich dazu einige Fragen:
  1. Kann ich mich darauf verlassen, dass p bei Nichtfinden immer die richtige Einfügeposition zurückliefert oder kann p (abhängig von gerader oder ungerader Gesamtmenge) um einen Eintrag falsch liegen? Ich habe vorsichtshalber eine Korrektur eingebaut (
    Delphi-Quellcode:
    If AnsiCompareText...
    , ist die nötig / wirksam?
  2. Die Liste hat eine Größenordnung von ca. 10.000 Einträgen. Ab welcher Größe ungefähr ist ein Neusortieren deutlich langsamer als ein Einfügen?
  3. Geht eigentlich ein Neusortieren deutlich schneller, wenn die Liste bis auf einen Eintrag bereits richtig sortiert ist?
  4. Ich muss TZiel nach verschiedenen Werten (Text,Zahl) finden / einsortieren. Wie mache ich das am besten? Mehrere Listen erzeugen, die nach dem gewünschten Wert sortieren und neue Einträge in jede Liste an der jeweils richtigen Position einfügen (klingt irgendwie alles schon nicht so gut)?

Danke!

stahli 17. Jul 2015 13:48

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Welche Delphi-Version nutzt Du denn?
(Solltest Du mal in Deinem Profil einstellen.)

Wenn es eine aktuelle mit Generics und einem TComparer ist dann wird das Ganze vielleicht etwas einfacher zu lösen sein.
Ein Bsp. mal hier: http://www.delphipraxis.net/1231518-post34.html

Benmik 17. Jul 2015 14:00

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Ja, wollt ich schon immer mal einstellen, ist hiermit geschehen. D2009. Generics gibts also, aber BinarySearch und TComparer offenbar noch nicht.

Sir Rufo 17. Jul 2015 14:05

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Doch in der Unit
Delphi-Quellcode:
Generics.Defaults

Benmik 17. Jul 2015 14:14

AW: Sortierte TObjectList - Einträge richtig einfügen
 
In der Tat!

Aber ach, Generics... ! MUSS DAS SEIN? Ich weiß natürlich, für die meisten hier sind das Pheromone...

stahli 17. Jul 2015 14:18

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Muss nicht sein.
Aber gerade für typisierte Listen ist das ganz komfortabel.

Die ganzen anderen Schweinereien mit generischen Klassen usw. vermeide ich auch lieber. Aber generische Listen sind schon nett (und unkompliziert).
Lediglich das schrittweise debuggen ist dann etwas seltsam (m.E.).

Benmik 17. Jul 2015 14:31

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Auf der anderen Seite liefert BinarySearch so ziemlich genau das, was ich will:
Zitat:

The method returns true if it finds the element and false otherwise. If found, Index contains the zero-based index of Item. If not found, Index contains the index of the first entry larger than Item.
Perfekt wär's, wenn das auch noch wär (was es aber nicht ist):
Zitat:

If there is more than one element in the list equal to Item, the index of the first match is returned in Index. This is the index of any of the matching items, not necessarily the first.
Aber sonst ziemlich genau das, was ich nachgebaut habe. Muss doch wohl meine erste generische Liste in Angriff nehmen.

Vielleicht noch eine Idee zu den anderen Fragen?

stahli 17. Jul 2015 14:48

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Gute Entscheidung. :thumb:
Generische Listen werden Dir hier helfen.

Du musst nur einen TComparer definieren, der Dir kleiner, gleich oder größer zu Deinen Items zurück liefert. Den Rest kannst Du der Binärsuchfunktion überlassen.

Eine Neusortierung musst Du eigentlich gar nicht machen, da Du jeden Eintrag direkt an die passende Stelle einsortieren kannst.
(Im Nachhinein bin ich nur nicht sicher, ob Extract aus meinem Beispiel vorhin die binäre Suche benutzt. Sonst müsste man eben explizit binär suchen und den Eintrag an dem gefundenen Index entfernen.)


Für unterschiedliche Sortierungen (nach Eigenschaft A oder B) habe ich keine Lösung parat.
Man könnte den Comparer unterschiedlich steuern (case ... of) und müsste die Liste dann aber bei einer Umschaltung komplett umsortieren.
Oder man verwaltet mehrere Listen mit Objektreferenzen und sortiert die binär verschieden. Muss man halt immer alle synchron halten und Einträge immer in allen einfügen bzw. entfernen.
Die beste Lösung hängt sicher vom Einzelfall ab. Wenn man sich eine Factory baut, die das Einfügen und Entfernen zentral übernimmt, kann die das synchronisieren der Listen natürlich schön automatisieren.

Ganz nützlich kann auch ein Dictionary sein, was idR. noch schneller als eine binäre Liste funktioniert.


Zu Listentypen will ich gleich nochmal auf meinen kürzlichen Link zu Video2Brain verweisen ... hierin: http://www.delphipraxis.net/1308861-post28.html
Die Trainerin fasst das m.E. ganz gut zusammen.

Sir Rufo 17. Jul 2015 14:49

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Delphi-Quellcode:
uses
  Generics.Collections,
  Generics.Defaults;

type
  TZiel = class(TObject)
    WERT1 : Word;
    WERT2 : Word;
    WERT3 : String;
    WERT4 : String;
    WERT5 : Cardinal;
    WERT6 : Int64;
    WERT7 : Int64;
  end;

  TZielListe = class( TObjectList<TZiel> )
  private
    function Compare( const L,R: TZiel) : Integer;
  public
    constructor Create( OwnsObjects: Boolean = true );
  end;

function TZielListe.Compare( const L,R: TZiel) : Integer;
begin
  Result := TComparer<string>.Default.Compare( L.Wert3, R.Wert3 );
end;

constructor TZielListe.Create( OwnsObjects: Boolean );
begin
  inherited Create( TComparer<TZiel>.Construct( Compare ), OwnsObjects );
end;

Benmik 17. Jul 2015 14:57

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Danke euch beiden! Sensationell.

Schließe mich dem an: Kaum macht man's richtig - schon funktioniert's. :thumb:

stahli 17. Jul 2015 15:00

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Dann wird das ja nochmal einfacher. :thumb:
(Wobei das bezüglich Lesbarkeit für normale Menschen schon etwas gewöhnungsbedürftig ist. ;-))

Könnte man im Compare dann auch per Case dynamisch die Sortierung umstellen? Und wenn ja, müsste die komplette Liste in dem Moment auch neu durchsortiert werden - richtig?

Sir Rufo 17. Jul 2015 15:14

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Die Liste wird mit dem Comparer sortiert, wenn man
Delphi-Quellcode:
TList<T>.Sort
aufruft.

Will ich eine andere Sortierung haben, dann mit
Delphi-Quellcode:
TList<T>.Sort( AComparer: IComparer<T> )
aufrufen.

Der Comparer, den man im Konstruktor mit angibt, sorgt nicht nur für die (Standard-)Sortierung, sondern damit wird auch die Gleichheit der Elemente ermittelt.
Delphi-Quellcode:
var
  Ziel1, Ziel2, Ziel3 : TZiel;
  ZielList : TZielList;

Ziel1 := TZiel.Create; // erste Instenz
Ziel1.Wert3 := 'Foo';
Ziel2 := TZiel.Create; // zweite Instanz
Ziel2.Wert3 := 'Foo';

// Ziel1 und Ziel2 sind unterschiedliche Instanzen

ZielList := TZielList.Create;

ZielList.Add( Ziel1 );
ZielList.IndexOf( Ziel1 ); // wie zu erwarten erhält man 0
ZielList.IndexOf( Ziel2 ); // und hier? auch eine 0!!!

ZielList.Contains( Ziel1 ); // liefert true
ZielList.Contains( Ziel2 ); // liefert auch true

Ziel3 := ZielList.Extract( Ziel2 ); // welche Referenz ist jetzt in Ziel3? Ziel1, Ziel2, nil?

if Ziel3 = nil then
  ShowMessage('Ich bin leer');
if Ziel3 = Ziel2 then
  ShowMessage( 'Ich bin Ziel2' );
if Ziel3 = Ziel1 then
  ShowMessage( 'Ich bin Ziel1' );
;)

Benmik 17. Jul 2015 15:27

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Und das am Freitagnachmittag!

Was ich - unter anderem :thumb: - nicht verstehe, ist, woher der Comparer weiß, dass der beim Vergleich der Objekte "TZiel" Ziel.Wert3 vergleichen muss / soll. Ich habe mich nämlich auch schon gefragt, wie man BinarySearch verwendet, wenn man doch gar nicht die Objekte, sondern deren einzelne Werte finden will. Bei stackoverflow habe ich eine Konstruktion mit Dummy (und auch noch mit einer anonymen Methode, heute bleibt mir nichts erspart) gefunden:
Delphi-Quellcode:
function SearchList(Wert:string; Liste:TZielListe): Integer;
var Dummy : TZiel;
begin
  if not Liste.BinarySearch(Dummy, Result, TDelegatedComparer<TZiel>.Construct(
      function (const L, R: TZiel): Integer
      begin
        Result := AnsiCompareText(L.Wert3,Wert);
      end)) then
    Result := -1;
end;
Geht das auch anders?

Sir Rufo 17. Jul 2015 15:54

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Du legst doch im Comparer fest, dass mit
Delphi-Quellcode:
TZiel.Wert3
verglichen werden soll
Delphi-Quellcode:
function (const L, R: TZiel): Integer
      begin
        Result := AnsiCompareText(L.Wert3,Wert);
      end
:gruebel:

Benmik 17. Jul 2015 15:59

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Ja, in dem Dummy-Beispiel. Mit dem Dummy wird das Problem umgangen, dass auf beiden Seiten TZiel erwartet wird, während man aber TZiel.Wert3 gegen einen frei gewählten Wert vergleichen lassen will. Das Beispiel funktioniert ja auch, es ist eben nur eine Krücke. Der Compiler beschwert sich auch, dass Dummy nicht initialisiert worden sei. Daher meine Frage, ob das auch eleganter geht.

Du verwendest auch Ziel.Wert3. Ich vermute, dass die Funktionen IndexOf und Contains alle Werte von Ziel vergleichen, um Gleichheit festzustellen. Die Funktionen würden also negativ ausfallen, wenn beispielsweise Ziel.Wert2 verschieden wäre (so vermute ich).

Sir Rufo 17. Jul 2015 16:09

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Du meinst sowas hier?
Delphi-Quellcode:
uses
  Generics.Collections,
  Generics.Defaults;

type
  TZiel = class(TObject)
    WERT1 : Word;
    WERT2 : Word;
    WERT3 : String;
    WERT4 : String;
    WERT5 : Cardinal;
    WERT6 : Int64;
    WERT7 : Int64;
  end;

  TZielListe = class( TObjectList<TZiel> )
  private
    function Compare( const L,R: TZiel) : Integer;
  public
    constructor Create( OwnsObjects: Boolean = true );
    function IndexOfWert3(const Value: string) : Integer;
  end;

function TZielListe.IndexOfWert3(const Value: string) : Integer;
var
  LItem : TZiel;
begin
  LItem := TZiel.Create;
  try
    LItem.Wert3 := Value;
    if not BinarySearch( 
      LItem,
      Result,
      TComparer<TZiel>.Construct(
        function (const L, R: TZiel): Integer
        begin
          Result := AnsiCompareText( L.Wert3, R.Wert3 );
        end ) ) then
      Result := -1;
  finally
    LItem.Free;
  end;
end;

function TZielListe.Compare( const L,R: TZiel) : Integer;
begin
  Result := TComparer<string>.Default.Compare( L.Wert3, R.Wert3 );
end;

constructor TZielListe.Create( OwnsObjects: Boolean );
begin
  inherited Create( TComparer<TZiel>.Construct( Compare ), OwnsObjects );
end;
Andererseits kannst du auch den Standard-Comparer nutzen, wenn der schon passt:
Delphi-Quellcode:
function TZielListe.IndexOfWert3(const Value: string) : Integer;
var
  LItem : TZiel;
begin
  LItem := TZiel.Create;
  try
    LItem.Wert3 := Value;
    Result := IndexOf( LItem );
  finally
    LItem.Free;
  end;
end;

function TZielListe.Compare( const L,R: TZiel) : Integer;
begin
  Result := AnsiCompareText( L.Wert3, R.Wert3 );
end;

constructor TZielListe.Create( OwnsObjects: Boolean );
begin
  inherited Create( TComparer<TZiel>.Construct( Compare ), OwnsObjects );
end;

Sir Rufo 17. Jul 2015 16:16

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Ich würde das allerdings gar nicht so kompliziert gestalten.

Erzeuge dir deine Instanzen und frage die Liste, ob so eine "gleiche" Instanz schon existiert
Delphi-Quellcode:
TList<T>.Contains
. Und wenn ja, dann kannst du die Instanz einfach an die Liste anfügen und sortieren lassen.

Benmik 17. Jul 2015 16:33

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Sir Rufo, du hast es drauf.

Verstehe ich deinen Nachsatz richtig? Wenn ich ein TZiel nach einem seiner 7 Felder einsortieren lassen möchte, dann werden sowohl Contains als auch IndexOf Erfolg melden, auch wenn die anderen 6 Felder nicht übereinstimmen, sofern das Feld 3 passt, da es im Comparer angegeben ist?
Durch Angabe von verschiedenen Comparern (was ein Deutsch!) kann ich nach verschiedenen Feldern suchen und einsortieren lassen?

P.S.: Man fragt sich natürlich, ob diese Frage nicht auch durch einen Blick in den Quellcode hätte ersetzt werden können...

Sir Rufo 17. Jul 2015 16:48

AW: Sortierte TObjectList - Einträge richtig einfügen
 
So ist es ... nur dass du den Comparer nicht mehr ändern kannst ... dann musst du das mit dem BinarySearch verwenden (dort kannst du dann den gewünschten Comparer angeben).

Oder du machst es ganz anders und zwar mit einem
Delphi-Quellcode:
TFunc<T1,T2,TResult>
:
Delphi-Quellcode:
function TZielList.IndexOf<T>( AValue: T; APredicate : TFunc<T,TZiel,Boolean> ) : Integer;
var
  LIdx: Integer;
  LItem: TZiel;
begin
  for LIdx := 0 to Count - 1 do
    if APredicate( AValue, Self[LIdx] ) then
    begin
      Result := LIdx;
      Exit;
    end;
  Result := -1;
end;
und du suchst einfach nur noch mit:
Delphi-Quellcode:
ZielList.IndexOf<string>(
  'MeinWert',
  function ( Value: string; Item: TZiel ) : Boolean
  begin
    Result := AnsiCompareText( Item.Wert3, Value );
  end );

ZielList.IndexOf<Word>(
  42,
  function ( Value: Word; Item: TZiel ) : Boolean
  begin
    Result := Item.Wert1 = Value;
  end );
Ich weiß, das sieht pervers aus ... ;)

stahli 17. Jul 2015 16:58

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

Zitat von Sir Rufo (Beitrag 1309068)
Ich weiß, das sieht pervers aus ... ;)

Endlich mal ein versöhnliches Zeichen der Einsicht! :mrgreen:

Ich gehe dann lieber immer einen verständlicheren Weg (so dass ich das dann auch nachvollziehen kann).
Wenn man solche Internas komplett versteht, hat das aber natürlich auch was. :stupid:

Benmik 17. Jul 2015 18:18

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Beeindruckend, aber vielleicht ein bisschen l'art pour l'art? Es gibt auch auch die Frage, warum der Rüde sich die Eier leckt, aber die wollen wir jetzt nicht weiter vertiefen.

Wenn mich nicht alles täuscht, dann ist das letzte Vexierspielchen ja auch keine binäre Suche mehr, sondern eine einfache Interation?

Da der Abend hereinbricht, komme ich jetzt zu dem Schluss, dass mir die Lösungen aus #13 und #16 am einfachsten erscheinen, die #13 ist kürzer, die #16 wohl sauberer. Für mich wird es wohl (aber man weiß, Sir Rufos Trickkiste ist noch lange nicht leer) eine modifizierte Form werden:
Delphi-Quellcode:
function TZielListe.SucheWert(const Wert:string;var P:Integer):Boolean;
var LItem:TZiel;
begin
  LItem := TZiel.Create;
  try
    LItem.Wert := Wert;
    Result := BinarySearch(
      LItem, p,
      TComparer<TZiel>.Construct(
        function (const L, R: TZiel): Integer
        begin
          Result := AnsiCompareText(L.Wert,R.Wert);
        end ));
  finally
    LItem.Free;
  end;
end;
So bekomme ich mit p auch das gefundene Element oder im Negativfalle die Einfügeposition zurück.
Eigentlich spricht auch nichts gegen die Dummy-Lösung, man spart sich das Create und Free und initialisert wegen des Compiler-Gemeckers einfach mit nil.

Stevie 17. Jul 2015 18:33

AW: Sortierte TObjectList - Einträge richtig einfügen
 
In Delphi 2009 lösen diese Generics Pheromone bei mir aber eher einen sehr starken Fluchtinstinkt aus :)

Benmik 17. Jul 2015 18:54

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Dagegen würden Kritiker einwenden, dass du weder das Konzept von Pheromonen noch das von Generics verstanden hast. Bei beiden wird bei entsprechend veranlagten Individuen von einer extremen Anziehung ausgegangen. Der Aaskäfer dreht durch, wenn eine Aaskäferin ihre Moleküle verstreut, insbesondere, wenn sie gerade von einer gut durchmadeten Leiche kommt. Und der Delphianer ab D2009 ... Aber genug. Pheromone haben ihre Zielgruppe, und zu der muss man halt gehören. :wink:

Stevie 17. Jul 2015 18:57

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

Zitat von Benmik (Beitrag 1309083)
Dagegen würden Kritiker einwenden, dass du weder das Konzept von Pheromonen noch das von Generics verstanden hast. Bei beiden wird bei entsprechend veranlagten Individuen von einer extremen Anziehung ausgegangen. Der Aaskäfer dreht durch, wenn eine Aaskäferin ihre Moleküle verstreut, insbesondere, wenn sie gerade von einer gut durchmadeten Leiche kommt. Und der Delphianer ab D2009 ... Aber genug. Pheromone haben ihre Zielgruppe, und zu der muss man halt gehören. :wink:

Eventuell sollten diese Kritiker nochmal die Definition von Pheromonen nachlesen - Anziehung ist nur eine Reaktion die sie auslösen können. 8-)
Und das Konzept von Generics hab ich wohl ganz gut verstanden - es geht darum, dass sie in Delphi 2009 einfach grottenhaft verbuggt sind.
Wir reden nochmal, wenn den Kritikern der Compiler das erste mal mit ner AV weggesegelt ist :)

Benmik 17. Jul 2015 19:42

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Oh je, es handelt sich also um Alarmpheromone.

Ich hab mich jetzt zu Folgendem entschlossen:
Delphi-Quellcode:
function TZielListe.FindeWert(const Wert:string;var P:Integer):Boolean;
var L:TZiel;
begin
  L     := TZiel.Create;
  L.Wert := Wert;
  p     := -1;
  try
    Result := BinarySearch(L, p, TComparer<TZiel>.Construct(
      function (const L, R: TZiel): Integer
      begin
        Result := AnsiCompareText(L.Wert,R.Wert);
      end));
  Finally
    L.Free;
  end;
end;

function TZielListe.AddSorted(const Ziel: TZiel): Boolean;
var P: Integer;
begin
  Result := Assigned(Ziel) and (Ziel.Wert <> '');
  If Result then
    begin
    FindeWert(Ziel.Wert,p);
    Result := (p > -1);
    If Result then
      Self.Insert(p,Ziel);
    end;
end;
Jetzt hoffe ich mal, von den AV verschont zu bleiben.

freimatz 23. Jul 2015 13:12

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

Zitat von Stevie (Beitrag 1309081)
In Delphi 2009 lösen diese Generics Pheromone bei mir aber eher einen sehr starken Fluchtinstinkt aus :)

Also bei mir löst Delphi 2009 Fluchtinstinkt aus. Wie kann man nur freiwillig mit so einem "Schrott" arbeiten? Ich mit XE-7 habe in der Regel keine Probleme. (Außer wenn ich siebenfach verschachtele Genercis verwenden will)

Benmik 31. Jul 2015 14:06

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Wenn du mittlerweile mit XE7 arbeitest, solltest du deine Signatur aktualisieren. Die Bezeichnung "Schrott" für Delphi 2009 finde ich ärgerlich und sehr unangemessen. Und "freiwillig" ist bei Hobbyprogrammierern immer recht relativ.

Perlsau 21. Sep 2015 11:08

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Moin allerseits, habe den Quellcode aus #9 in meinen zu integrieren versucht. Bei mir sieht das dann so aus:
Delphi-Quellcode:
UNIT ServerLogFiles;

INTERFACE

USES
  Windows, Classes, Messages, SysUtils, StrUtils, Generics.Collections, Generics.Defaults, Variants,
  LogFiles; // Klasse TLogFiles

TYPE
  TFileListe = CLASS(Generics.Collections.TObjectList<TLogFiles>)
    PRIVATE
      Function Compare(Item1, Item2 : TLogFiles): Integer;
    PUBLIC
      Constructor Create(OwnsObjects : Boolean = true);
  END;

TYPE
  TServerLogFiles = CLASS

  PRIVATE { Private-Deklarationen }

      FileList : TFileListe;
      ...
  END;

IMPLEMENTATION

{ TFileListe }

Function TFileListe.Compare(Item1, Item2 : TLogFiles): Integer;
begin
  Result := TComparer<String>.Default.Compare(Item1.FileName, Item2.FileName);
end;

Constructor TFileListe.Create(OwnsObjects: Boolean);
begin
 inherited Create(TComparer<TLogFiles>.Construct(Compare), OwnsObjects); // Fehler
end;

{ TSERVERLOGFILES }

...

end.
Beim Compilieren erhalte ich im Constuctor von TFileListe diesen Fehler bei (Compare):
ServerLogFiles.pas(96): E2010 Inkompatible Typen: 'TComparison<LogFiles.TLogFiles>' und 'Procedure of object'

Was mache ich da falsch?

Sir Rufo 21. Sep 2015 11:26

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Du hast das
Delphi-Quellcode:
const
vor
Delphi-Quellcode:
Item1, Item2
vergessen ;)

Perlsau 21. Sep 2015 11:30

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Ach du große Schande ... hab ich's doch gleich geahnt, daß es mal wieder ein Flüchtigkeitsfehler sein muß :oops:

Danke für deine schnelle Hilfe :thumb:

Sir Rufo 21. Sep 2015 11:32

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

Zitat von Perlsau (Beitrag 1316481)
Ach du große Schande ... hab ich's doch gleich geahnt, daß es mal wieder ein Flüchtigkeitsfehler sein muß :oops:

Danke für deine schnelle Hilfe :thumb:

Passiert mir auch mal ganz gerne, darum war der Blick schon gleich geschärft ;)

mkinzler 21. Sep 2015 11:39

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Es wird eine Prozedur und keine Methode erwartet

Sir Rufo 21. Sep 2015 11:58

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

Zitat von mkinzler (Beitrag 1316486)
Es wird eine Prozedur und keine Methode erwartet

Hmmm, ein
Delphi-Quellcode:
reference to ...
darf sowohl als auch sein ...

Perlsau 21. Sep 2015 12:05

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

Zitat von mkinzler (Beitrag 1316486)
Es wird eine Prozedur und keine Methode erwartet

So hatte ich die Fehlermeldung eigentlich auch erst verstanden. Doch auch eine Auslagerung der Compare-Function aus der Klasse hat nichts gebracht, Sir Rufo's Lösung dagegen schon: Jetzt funktioniert meine Sortierung auch mit der Methode Compare. Der Klasse hab ich noch eine Public-Variable SortId spendiert, die beim Klick auf das jeweilige Titelfeld des Stringgrids gesetzt wird. Damit reduziert sich meine Sortierung auf drei Zeilen in der aufrufenden Klasse:
Delphi-Quellcode:
Function TFileListe.Compare(Const Item1, Item2 : TLogFiles) : Integer;
begin
  Case SortId Of
   0 : Result := TComparer<Integer>.Default.Compare(Item1.FileId, Item2.FileId);
   1 : Result := TComparer<String>.Default.Compare(Item1.FileName, Item2.FileName);
   2 : Result := TComparer<String>.Default.Compare(Item1.FileType, Item2.FileType);
   3 : Result := TComparer<Int64>.Default.Compare(Item1.FileSize, Item2.FileSize);
   4 : Result := TComparer<TDateTime>.Default.Compare(Item1.FileDate, Item2.FileDate);
   5 : Result := TComparer<Boolean>.Default.Compare(Item1.FileDown, Item2.FileDown);
  End;
end;

Procedure TServerLogFiles.GridMouseUp(Grid: TJvStringGrid; Btn: TMouseButton; x, y: Integer);
Var
  Spalte,
  Zeile  : Longint;
  Saved  : Boolean;
  DbDatum : TDateTime;
  DbSize : Int64;
  i      : Integer;

begin
  Grid.MouseToCell(x, y, Spalte, Zeile);
  i := Zeile -1;
  If Btn = mbLeft Then
  Begin
    If Zeile = 0 Then
    Begin // Sortierung
      FileList.SortId := Spalte;
      FileList.Sort;
      GetFileListInGrid(Grid);
    End;
 
    If (Zeile > 0) And (Spalte = 5) Then
    Begin // Down-Markierung
      DbSize := DatMod.View_DownFiles.FieldByName('DATEISIZE').AsInteger;
      DbDatum := DatMod.View_DownFiles.FieldByName('DATEIDATUM').AsDateTime;
      Saved  := DatMod.View_DownFiles.Locate('DATEI;DATEITYP',
                                              VarArrayOf([FileList[i].FileName, FileList[i].FileType]),[]);
      If Saved Then
      Begin
        Grid.Hint    := 'Size: ' + GLD.IntToStrPunkte(DbSize) + ' / Datum: ' + DateTimeToStr(DbDatum);
        Grid.ShowHint := True;
      End Else
      Begin
        Grid.Hint    := '';
        Grid.ShowHint := False;
      End;

      FileList[i].FileDown := Not FileList[i].FileDown;
      GetFileListInGrid(Grid);
    End;
  End;
end;

Sir Rufo 21. Sep 2015 12:30

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Man kann zum Sortieren der Liste auch einen Comparer mitgeben
Delphi-Quellcode:
TList<T>.Sort( const Comparer: IComparer<T> );
.

Der interne Comparer der Liste ist eigentlich für die Identität da. So wird dieser z.B. bei
Delphi-Quellcode:
IndexOf
oder
Delphi-Quellcode:
Contains
verwendet (unabhängig davon, wie die Liste jetzt sortiert ist).

Perlsau 21. Sep 2015 12:39

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Hatte ich zuvor bereits versucht, allerdings wieder obige Fehlermeldung erhalten, wobei man hier vermutlich den alternativen Comparer nicht als Klassenmethode deklarieren darf. Da ich hier aber weder was einfügen noch IndexOf verwenden muß, bleibe ich vorerst bei meiner zweckentfremdenden Variante :stupid:

Nochmals ganz großen Dank für deine Unterstützung, denn jetzt hab ich immerhin was dazugelernt :thumb:

Sir Rufo 21. Sep 2015 12:49

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Doch geht schon ;)
Delphi-Quellcode:
unit Unit1;

interface

uses
  Generics.Collections,
  Generics.Defaults;

type
  TLogFile = class
  private
    FFileId : Integer;
    FFileName: string;
  public
    property FileId : Integer read FFileId;
    property FileName: string read FFileName;
  public
    class function IdentityCompare( const L, R: TLogFile ): Integer; static;
    class function NameCompare( const L, R: TLogFile ): Integer; static;
  end;

  TLogFileList = class( TObjectList<TLogFile> )
  public
    constructor Create( AOwnsObjects: Boolean = True );
  end;

implementation

{ TLogFile }

class function TLogFile.IdentityCompare( const L, R: TLogFile ): Integer;
begin
  Result := TComparer<Integer>.default.Compare( L.FFileId, R.FFileId );
end;

class function TLogFile.NameCompare( const L, R: TLogFile ): Integer;
begin
  Result := TComparer<string>.default.Compare( L.FFileName, R.FFileName );
end;

{ TLogFileList }

constructor TLogFileList.Create;
begin
  inherited Create( TComparer<TLogFile>.Construct( TLogFile.IdentityCompare ), AOwnsObjects );
end;

end.
wenn man die Methoden als
Delphi-Quellcode:
static
markiert ;)

Zusätzlich könnte man bei der Klasse auch noch die gewünschten Comparer als
Delphi-Quellcode:
class property
hinterlegen ... kommt halt darauf an :)

Stevie 21. Sep 2015 19:05

AW: Sortierte TObjectList - Einträge richtig einfügen
 
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.

TiGü 22. Sep 2015 09:10

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

Zitat von Stevie (Beitrag 1316531)
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)?

Benmik 22. Sep 2015 21:27

AW: Sortierte TObjectList - Einträge richtig einfügen
 
Möglicherweise
Delphi-Quellcode:
class function TLogFile.IdentityCompare( const L, R: TLogFile ): Integer;
begin
  Result := L.FFileId - R.FFileId;
end;
zum Beispiel ?


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:09 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