TObjectList sortieren

Für Fragen von Einsteigern und Programmieranfängern...
Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1436
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: TObjectList sortieren

Beitrag von fliegermichl »

So, jetzt aber. Man beachte den Aufruf von Sort.

Code: Alles auswählen

program testproject;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, Generics.Collections, Generics.Defaults, Math;

type

  { TStressEntry }

  TStressEntry = class
    ID: integer;
    stress: double;
  end;

  TStressList = specialize TObjectList<TStressEntry>;

var
  i: integer;
  NodeID: integer;
  Stress: double;
  StrLst, Line: TstringList;
  str: string;
  StressEntry: TStressEntry;
  StressList: TStressList;
  L1, L2 : string;

function Compare(constref ALeft, ARight: TStressEntry): Integer;
begin
  Result := ALeft.Id - ARight.Id;
end;

begin
  StressList := TStressList.Create;

  StrLst := TStringList.Create;

  //Simulates LoadFromFile
  StrLst.Add('513384 -4,821229171753e+01');
  StrLst.Add('806394 -4,821158599854e+01');
  StrLst.Add('513934 -4,778438568115e+01');
  StrLst.Add('806944 -4,778303909302e+01');
  StrLst.Add('809518 -4,754859924316e+01');
  StrLst.Add('516512 -4,754709625244e+01');
  StrLst.Add('517078 -4,745193862915e+01');
  StrLst.Add('810084 -4,744944381714e+01');
  StrLst.Add('513247 -4,690411376953e+01');
  StrLst.Add('806257 -4,690361785889e+01');
  StrLst.Add('513851 -4,689748382568e+01');
  StrLst.Add('806861 -4,689499282837e+01');
  StrLst.Add('513713 -4,639287948608e+01');
  StrLst.Add('806723 -4,639037704468e+01');
  StrLst.Add('514801 -4,603351974487e+01');
  StrLst.Add('807807 -4,602876281738e+01');
  StrLst.Add('515922 -4,540652465820e+01');
  StrLst.Add('808928 -4,540190505981e+01');

  for i:=0 to StrLst.Count-1 do
  begin
    str := StrLst[i];

    Line := TStringList.Create;
    Line.DelimitedText := str;

    L1 := Line[0];
    L2 := Line[1];
    NodeID := StrToInt(L1);
    Stress := StrToFloat(L2);

    writeln(Format('  %2d:   %6d -- %12.6f',[i,NodeID,Stress]));

    StressEntry := TStressEntry.Create;

    StressEntry.ID := NodeID;
    StressEntry.stress := Stress;

    StressList.Add(StressEntry);

    Line.Free;
  end;

  writeln(Format(' length of StressList: %d',[StressList.Count]));

  for i:=0 to StressList.Count-1 do
  begin
    writeln(Format(' StressList[%2d]:   %6d -- %12.6f',
      [i,StressList[i].ID,StressList[i].Stress]));
  end;

  // Now sort
  StressList.Sort(specialize TComparer<TStressEntry>.Construct(@Compare));
  //StressList.Sort(@CompareStressList);      // <--- hier stoppt der Compiler

  for i:=0 to StressList.Count-1 do
  begin
    writeln(Format('NOW SORTED - StressList[%2d]:   %6d -- %12.6f',
      [i,StressList[i].ID,StressList[i].Stress]));
  end;
  ReadLn;
end.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1436
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: TObjectList sortieren

Beitrag von fliegermichl »

Alternativ kann man die Sortierfunktion schon beim erzeugen der Liste angeben und ruft dann Sort ohne Parameter auf.

Code: Alles auswählen

  StressList := TStressList.Create(specialize TComparer<TStressEntry>.Construct(@Compare));
 ...
  StressList.Sort;
 

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 338
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon (Windows wenn notwendig), Lazarus 3.0 FPC 3.3.1

Re: TObjectList sortieren

Beitrag von Niesi »

Ich persönlich würde die Listen in StringLists einlesen, sortieren und DANN weiter bearbeiten ...

Bildschirmfoto vom 2024-03-14 10-20-10.png
Bildschirmfoto vom 2024-03-14 10-20-10.png (70.72 KiB) 4600 mal betrachtet
Zuletzt geändert von Niesi am Do 14. Mär 2024, 10:21, insgesamt 1-mal geändert.
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1436
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: TObjectList sortieren

Beitrag von fliegermichl »

Was mir bei dieser ganzen Geschichte noch nicht so ganz klar ist. Wenn ich sage, das TStressList eine spzialisierte Version von TObjectList mit Einträgen vom Typ TStressEntry sein soll, wieso muß ich das dann beim sortieren bzw. erzeugen der Liste nochmal angeben?

Benutzeravatar
photor
Beiträge: 445
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: TObjectList sortieren

Beitrag von photor »

Niesi hat geschrieben:
Do 14. Mär 2024, 09:23
Habe ich das richtig verstanden: Du hast mehrere Textfiles, in denen pro Zeile je eine Knotennummer und - durch Leerzeichen getrennt - ein Spannungswert stehen?

Die führst Du zu einem Textfile zusammen und brauchst die dann nach Knotennummer sortiert?
Andersrum:
  • erst die Files einzeln einlesen
  • sortieren nach Knotennummer
  • dann zusammenführen (die Spannungswerte werden in einen Vector/Tensor gepackt)
Mir geht es im Moment darum, die eingelesene Liste zu sortieren.

Ciao,
Photor

Benutzeravatar
photor
Beiträge: 445
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: TObjectList sortieren

Beitrag von photor »

fliegermichl hat geschrieben:
Do 14. Mär 2024, 10:01
So, jetzt aber. Man beachte den Aufruf von Sort.

Code: Alles auswählen

program testproject;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, Generics.Collections, Generics.Defaults, Math;

type

  { TStressEntry }

  TStressEntry = class
    ID: integer;
    stress: double;
  end;

  TStressList = specialize TObjectList<TStressEntry>;

var
  i: integer;
  NodeID: integer;
  Stress: double;
  StrLst, Line: TstringList;
  str: string;
  StressEntry: TStressEntry;
  StressList: TStressList;
  L1, L2 : string;

function Compare(constref ALeft, ARight: TStressEntry): Integer;
begin
  Result := ALeft.Id - ARight.Id;
end;

begin
  StressList := TStressList.Create;

  StrLst := TStringList.Create;

  //Simulates LoadFromFile
  StrLst.Add('513384 -4,821229171753e+01');
  StrLst.Add('806394 -4,821158599854e+01');
  StrLst.Add('513934 -4,778438568115e+01');
  StrLst.Add('806944 -4,778303909302e+01');
  StrLst.Add('809518 -4,754859924316e+01');
  StrLst.Add('516512 -4,754709625244e+01');
  StrLst.Add('517078 -4,745193862915e+01');
  StrLst.Add('810084 -4,744944381714e+01');
  StrLst.Add('513247 -4,690411376953e+01');
  StrLst.Add('806257 -4,690361785889e+01');
  StrLst.Add('513851 -4,689748382568e+01');
  StrLst.Add('806861 -4,689499282837e+01');
  StrLst.Add('513713 -4,639287948608e+01');
  StrLst.Add('806723 -4,639037704468e+01');
  StrLst.Add('514801 -4,603351974487e+01');
  StrLst.Add('807807 -4,602876281738e+01');
  StrLst.Add('515922 -4,540652465820e+01');
  StrLst.Add('808928 -4,540190505981e+01');

  for i:=0 to StrLst.Count-1 do
  begin
    str := StrLst[i];

    Line := TStringList.Create;
    Line.DelimitedText := str;

    L1 := Line[0];
    L2 := Line[1];
    NodeID := StrToInt(L1);
    Stress := StrToFloat(L2);

    writeln(Format('  %2d:   %6d -- %12.6f',[i,NodeID,Stress]));

    StressEntry := TStressEntry.Create;

    StressEntry.ID := NodeID;
    StressEntry.stress := Stress;

    StressList.Add(StressEntry);

    Line.Free;
  end;

  writeln(Format(' length of StressList: %d',[StressList.Count]));

  for i:=0 to StressList.Count-1 do
  begin
    writeln(Format(' StressList[%2d]:   %6d -- %12.6f',
      [i,StressList[i].ID,StressList[i].Stress]));
  end;

  // Now sort
  StressList.Sort(specialize TComparer<TStressEntry>.Construct(@Compare));
  //StressList.Sort(@CompareStressList);      // <--- hier stoppt der Compiler

  for i:=0 to StressList.Count-1 do
  begin
    writeln(Format('NOW SORTED - StressList[%2d]:   %6d -- %12.6f',
      [i,StressList[i].ID,StressList[i].Stress]));
  end;
  ReadLn;
end.
Das werde ich probieren (ich denke aber, dass hast du probiert) - Danke. Und dann versuchen zu verstehen.

Ciao,
Photor

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 338
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon (Windows wenn notwendig), Lazarus 3.0 FPC 3.3.1

Re: TObjectList sortieren

Beitrag von Niesi »

photor hat geschrieben:
Do 14. Mär 2024, 15:59
Niesi hat geschrieben:
Do 14. Mär 2024, 09:23
Habe ich das richtig verstanden: Du hast mehrere Textfiles, in denen pro Zeile je eine Knotennummer und - durch Leerzeichen getrennt - ein Spannungswert stehen?

Die führst Du zu einem Textfile zusammen und brauchst die dann nach Knotennummer sortiert?
Andersrum:
  • erst die Files einzeln einlesen
  • sortieren nach Knotennummer
  • dann zusammenführen (die Spannungswerte werden in einen Vector/Tensor gepackt)
Mir geht es im Moment darum, die eingelesene Liste zu sortieren.

Ciao,
Photor
Ja, genau so habe ich es in meiner zweiten Antwort gemeint: Du liest jedes File in eine Stringlist ein (SL1, SL2, SL3: TStringlist), sortierst die und fügst die dann zusammen.
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
photor
Beiträge: 445
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: TObjectList sortieren

Beitrag von photor »

Niesi hat geschrieben:
Do 14. Mär 2024, 16:21
Ja, genau so habe ich es in meiner zweiten Antwort gemeint: Du liest jedes File in eine Stringlist ein (SL1, SL2, SL3: TStringlist), sortierst die und fügst die dann zusammen.
Hatte ich auch kurz überlegt. Da aber im geplanten Programm noch sehr viel mehr Files eingelesen und sortiert und dann weiter verarbeitet müssen, hatte ich Bedenken, dass StringLists (und das sortieren von Strings) zu aufwändig werden könnte.

Und ich hatte mir das Sortieren der ObjectList einfacher vorgestellt. (und so wirklich schön ist das noch nicht - aber tut erstmal - s.u.).
photor hat geschrieben:
Do 14. Mär 2024, 16:02
fliegermichl hat geschrieben:
Do 14. Mär 2024, 10:01
So, jetzt aber. Man beachte den Aufruf von Sort.

Code: Alles auswählen

program testproject;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, Generics.Collections, Generics.Defaults, Math;

type

  { TStressEntry }

...

  // Now sort
  StressList.Sort(specialize TComparer<TStressEntry>.Construct(@Compare));

...

Das werde ich probieren (ich denke aber, dass hast du probiert) - Danke. Und dann versuchen zu verstehen.
Nachdem ich dann das Generics.Defaults in der uses-Zeile entdeckt hatte, hat das auch gut funktioniert.

Bis hierher vielen Dank allen, die mir geholfen haben,
Photor

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 338
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon (Windows wenn notwendig), Lazarus 3.0 FPC 3.3.1

Re: TObjectList sortieren

Beitrag von Niesi »

photor hat geschrieben:
Do 14. Mär 2024, 17:09


Hatte ich auch kurz überlegt. Da aber im geplanten Programm noch sehr viel mehr Files eingelesen und sortiert und dann weiter verarbeitet müssen, hatte ich Bedenken, dass StringLists (und das sortieren von Strings) zu aufwändig werden könnte.

Wenn die Daten so vorliegen, wie in Deinem Beispiel, dann ist das Sortieren in einer StringList mit

"MyStringList.Sort"

erledigt.

Das weißt Du, oder?
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1436
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: TObjectList sortieren

Beitrag von fliegermichl »

Niesi hat geschrieben:
Do 14. Mär 2024, 19:02
photor hat geschrieben:
Do 14. Mär 2024, 17:09


Hatte ich auch kurz überlegt. Da aber im geplanten Programm noch sehr viel mehr Files eingelesen und sortiert und dann weiter verarbeitet müssen, hatte ich Bedenken, dass StringLists (und das sortieren von Strings) zu aufwändig werden könnte.

Wenn die Daten so vorliegen, wie in Deinem Beispiel, dann ist das Sortieren in einer StringList mit

"MyStringList.Sort"

erledigt.

Das weißt Du, oder?
Dann werden aber Strings sortiert und da ist 1000 kleiner als 2.

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 338
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon (Windows wenn notwendig), Lazarus 3.0 FPC 3.3.1

Re: TObjectList sortieren

Beitrag von Niesi »

fliegermichl hat geschrieben:
Fr 15. Mär 2024, 07:41

Dann werden aber Strings sortiert und da ist 1000 kleiner als 2.
Das ist richtig - deshalb schrieb ich: "Wenn die Daten so vorliegen, wie in Deinem Beispiel, dann ..."

Es ist halt wie immer: Die, die programmieren möchten, müssen wissen, was sie tun ... :mrgreen:

Ich habe noch einige Zeilen hinzugefügt - so liefe es sehr, sehr einfach.


Bildschirmfoto vom 2024-03-15 08-02-24.png
Bildschirmfoto vom 2024-03-15 08-02-24.png (146.61 KiB) 4553 mal betrachtet
Dateianhänge
SortStringList.7z
(163.71 KiB) 54-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

kirchfritz
Beiträge: 172
Registriert: Mo 3. Jan 2011, 13:34
OS, Lazarus, FPC: Win10 (L 3.0 FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Nürnberg

Re: TObjectList sortieren

Beitrag von kirchfritz »

Niesi hat geschrieben:
Fr 15. Mär 2024, 08:05
fliegermichl hat geschrieben:
Fr 15. Mär 2024, 07:41

Dann werden aber Strings sortiert und da ist 1000 kleiner als 2.
Das ist richtig - deshalb schrieb ich: "Wenn die Daten so vorliegen, wie in Deinem Beispiel, dann ..."

Es ist halt wie immer: Die, die programmieren möchten, müssen wissen, was sie tun ... :mrgreen:

Ich habe noch einige Zeilen hinzugefügt - so liefe es sehr, sehr einfach.



Bildschirmfoto vom 2024-03-15 08-02-24.png

Und fügt man noch SL1.Sorted := true; ein, dann ist schon die SL1-Stringliste direkt nach dem Laden der einzelnen String sortiert, und man muss sich um das Sortieren selbst keine weiteren Gedanken machen
Bildschirmfoto-2024-03-15.png
Bildschirmfoto-2024-03-15.png (15.67 KiB) 4545 mal betrachtet

Benutzeravatar
photor
Beiträge: 445
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: TObjectList sortieren

Beitrag von photor »

Hallo Forum,

schön, dass weiter diskutiert wird. Ich lese weiter mit - und lerne. Danke dafür.

Warum habe ich nicht die StringList direkt sortieren wollen? Die meisten Argumente sind schon genannt worden: es werden dann halt Strings sortiert.

Das hat halt den Nachteil, dass die Reihenfolge falsch sein könnte[1]; die NodeID startet möglicherweise irgendwo bei 1 und und kann einige Millionen betragen (das ist bei FE leider so).
[1] Wenn die Sortierung immer gleich ist, kann man ja trotzdem die Spannungswerte den Knoten zuordnen. Aber ...

Dann habe ich im Beispiel nur ein abgespecktes Beispiel angegeben. Im realen Anwendungsfall. Es werden später dann aber deutlich mehr Files eingelesen (und sortiert). Da war dann (bei mir) auch die Frage, wie effektive ist es, String-Daten zu behandeln anstatt (Long)Integer. Der native Datentyp für solche Nummern ist nun mal ein Integer (und Floats für die Spannungswerte). Diese Datentypen würde ich dann auch gerne verwenden - Daher die ObjectList mit ensprechenden Einträgen..
(ich kämpfe seit langem mit einem alten Tool, in dem alle Daten in StringLists vorgehalten werden, die dann zum Rechnen konvertiert werden müssen und das Ergebnis wird dann wieder - als String - in einer StringList gespeichert - mit sehr großen Daten. Extrem ineffektive.)

Ciao,
Photor

Antworten