Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi Sortieren eines Array of record (https://www.delphipraxis.net/215793-sortieren-eines-array-record.html)

ebi 8. Sep 2024 04:03

Sortieren eines Array of record
 
Hallo,

wie kann ich das GCodeB: array of TCode numerisch (G0, G1, ... G9, G10, G11 ...) sortieren?

Vielen Dank.

Delphi-Quellcode:
unit steuerung;

interface

type
  TCode = record
    Wort: string;
    Bezeichnung: string;
  end;

  TSteuerung = class
  const
    Ebene: array [1 .. 3] of string = ('G17', 'G18', 'G19');
  public
    Name: string;
    Nullpunkt: array of string;
    Parameter: array of string;
    Wegbedingung: array of TCode;
    Schaltfunktion: array of TCode;
    TAdresse: array of TCode;
    constructor Create; overload;
    constructor Create(Value: string); overload;
  end;

const
  GCodeB: array [1 .. 35] of TCode = (
    (Wort: 'G0'; Bezeichnung: 'Verfahrweg im Eilgang'),
    (Wort: 'G1'; Bezeichnung: 'Linearinterpolation im Arbeitsgang'),
    (Wort: 'G2'; Bezeichnung: 'Kreisinterpolation im Uhrzeigersinn'),
    (Wort: 'G3'; Bezeichnung: 'Kreisinterpolation im Gegenuhrzeigersinn'),
    (Wort: 'G4'; Bezeichnung: 'Verweildauer'),
    (Wort: 'G9'; Bezeichnung: 'Genauhalt'),
    (Wort: 'G14'; Bezeichnung: 'Werkzeugwechselpunkt (WWP) anfahren'),
    (Wort: 'G50'; Bezeichnung: 'Aufheben der inkrementellen Nullpunktverschiebung und Drehungen'),
    (Wort: 'G53'; Bezeichnung: 'Alle Nullpunktverschiebungen und Drehungen aufheben'),
    (Wort: 'G22'; Bezeichnung: 'Unterprogrammaufruf'),
    (Wort: 'G23'; Bezeichnung: 'Programmteilwiederholung'),
    (Wort: 'G30'; Bezeichnung: 'Umspannen/Gegenspindelübernahme'),
    (Wort: 'G10'; Bezeichnung: 'Verfahren im Eilgang mit Polarkoordinaten'),
    (Wort: 'G11'; Bezeichnung: 'Linearinterpolation mit Polarkoordinaten'),
    (Wort: 'G12'; Bezeichnung:
    'Kreisinterpolation im Uhrzeigersinn mit Polarkoordinaten mit angetriebenem Werkzeug'),
    (Wort: 'G13'; Bezeichnung: 'Kreisinterpolation im Gegenuhrzeigersinn mit Polarkoordinaten'),
    (Wort: 'G45'; Bezeichnung: 'lineares tangentiales Anfahren an einer Kontur'),
    (Wort: 'G46'; Bezeichnung: 'lineares tangentiales Abfahren an einer Kontur'),
    (Wort: 'G47'; Bezeichnung: 'tangentiales Anfahren im Viertelskreis'),
    (Wort: 'G92'; Bezeichnung: 'Drehzahlbegrenzung'),
    (Wort: 'G94'; Bezeichnung: 'Vorschubgeschwindigkeit in mm/mni (Adresse: F)'),
    (Wort: 'G95'; Bezeichnung: 'Vorschub in mm (Adresse: F, opional E)'),
    (Wort: 'G96'; Bezeichnung: 'konst. Schnittgeschwindigkeit in m/min (Adresse: S)'),
    (Wort: 'G97'; Bezeichnung: 'konstante Drehzahl in 1/min (Adresse: S)'),
    (Wort: 'G70'; Bezeichnung: 'Umschalten auf Maßeinheit Zoll (inch)'),
    (Wort: 'G71'; Bezeichnung: 'Umschalten auf Maßeinheit Millimeter (mm)'),
    (Wort: 'G90'; Bezeichnung: 'absolute Maßangabe'),
    (Wort: 'G91'; Bezeichnung: 'Kettenmaßangabe'),
    (Wort: 'G80'; Bezeichnung: 'Abwahl einer Bearbeitungszyklus-Konturbeschreibung'),
    (Wort: 'G40'; Bezeichnung: 'Abwahlder Schneidenradiuskorrektur (SRK)'),
    (Wort: 'G41'; Bezeichnung: 'SRK links von der programmierten Kontur'),
    (Wort: 'G42'; Bezeichnung: 'SRK rechts von der programmierten Kontur'),
    (Wort: 'G48'; Bezeichnung: 'tangentiales Abahren im Viertelkreis'),
    (Wort: 'G16'; Bezeichnung: 'inkrementelle Drehung der aktuellen Bearbeitungsebene'),
    (Wort: 'G17'; Bezeichnung: 'Ebenenanwahl mit maschinenfesten Raumwinkeln'));

Uwe Raabe 8. Sep 2024 10:19

AW: Sortieren eines Array of record
 
Ich gehe mal davon aus, dass die Sortierung zur Laufzeit erfolgen soll. Um die Konstantendeklaration zu sortieren, hilft am Ende nur manuelles Verschieben der Zeilen.

Für die Sortierung zur Laufzeit benötigen wir ein dynamisches Array, was am einfachsten generisch als
Delphi-Quellcode:
TArray<TCode>
deklariert werden kann. In dieses kopieren wir die Werte aus GCodeB und sortieren es dann mit Hilfe der in System.Generics.Default und System.Generics.Collection deklarierten Klassen. Damit die Records auch numerisch sortiert werden, verwenden wir die in System.Sysutils deklarierte string-Helper Funktion
Delphi-Quellcode:
Compare
mit der Option
Delphi-Quellcode:
coDigitAsNumbers
.
Delphi-Quellcode:
function GCodeBSorted: TArray<TCode>;
begin
  SetLength(Result, Length(GCodeB));
  for var I := 0 to Length(Result) - 1 do
    Result[I] := GCodeB[Low(GCodeB) + I];
  TArray.Sort<TCode>(Result, TDelegatedComparer<TCode>.Create(
    function(const Left, Right: TCode): Integer
    begin
      Result := string.Compare(Left.Wort, Right.Wort, [coDigitAsNumbers]);
    end));
end;
Dabei ist zu beachten, dass das dynamische Array immer mit dem Index 0 beginnt, während das GCodeB ja als
Delphi-Quellcode:
array [1 .. 35] of TCode
deklariert ist. Das ist beim Zugriff auf das sortierte Array zu beachten. Hier ein simples Beispiel für den Funktionsaufruf und die Ausgabe des sortierten Arrays:
Delphi-Quellcode:
    var arr := GCodeBSorted;
    for var rec in arr do
      Writeln(rec.Wort, ': ', rec.Bezeichnung);

ebi 8. Sep 2024 10:37

AW: Sortieren eines Array of record
 
Hallo Hr. Raabe,

vielen Dank, werde versuchen Ihren Quellcode zuverstehen.

Herzliche Grüße.

Uwe Raabe 8. Sep 2024 10:55

AW: Sortieren eines Array of record
 
Zitat:

Zitat von ebi (Beitrag 1540697)
Hallo Hr. Raabe

Hier im Forum sind wir alle per Du.

ebi 8. Sep 2024 12:39

AW: Sortieren eines Array of record
 
Hallo Uwe,

vielen Dank.

Wie muss ich das bei mir einbinden?

Delphi-Quellcode:
procedure TForm_Main.MyObjects_default();
var
  Din, Pal: TSteuerung;
  I: integer;
begin
  // TSteuerung: DIN
  begin
    Din := TSteuerung.Create('DIN');
    SetLength(Din.Nullpunkt, 4);
    Din.Nullpunkt[0] := 'G54';
    Din.Nullpunkt[1] := 'G55';
    Din.Nullpunkt[2] := 'G56';
    Din.Nullpunkt[3] := 'G57';
    SetLength(Din.Parameter, 0);
    SetLength(Din.TAdresse, 0);

    SetLength(Din.Wegbedingung, Length(GCodeA));
    for I := 0 to Length(GCodeA) - 1 do
      begin
        Din.Wegbedingung[I].Wort := GCodeA[I + 1].Wort;
        Din.Wegbedingung[I].Bezeichnung := GCodeA[I + 1].Bezeichnung;
      end;

    SetLength(Din.Schaltfunktion, Length(MCodeA));
    for I := 0 to Length(MCodeA) - 1 do
      begin
        Din.Schaltfunktion[I].Wort := MCodeA[I + 1].Wort;
        Din.Schaltfunktion[I].Bezeichnung := MCodeA[I + 1].Bezeichnung;
      end;
  end;

  // TSteuerung: PAL
  begin
    Pal := TSteuerung.Create('PAL');
    SetLength(Pal.Nullpunkt, 6);
    Pal.Nullpunkt[0] := 'G54';
    Pal.Nullpunkt[1] := 'G55';
    Pal.Nullpunkt[2] := 'G56';
    Pal.Nullpunkt[3] := 'G57';
    Pal.Nullpunkt[4] := 'G58';
    Pal.Nullpunkt[5] := 'G59';
    SetLength(Pal.Parameter, 0);

    SetLength(Pal.Wegbedingung, Length(GCodeB));
    for I := 0 to Length(GCodeB) - 1 do
      begin
        Pal.Wegbedingung[I].Wort := GCodeB[I + 1].Wort;
        Pal.Wegbedingung[I].Bezeichnung := GCodeB[I + 1].Bezeichnung;
      end;

    SetLength(Pal.Schaltfunktion, Length(MCodeB));
    for I := 0 to Length(MCodeB) - 1 do
      begin
        Pal.Schaltfunktion[I].Wort := MCodeB[I + 1].Wort;
        Pal.Schaltfunktion[I].Bezeichnung := MCodeB[I + 1].Bezeichnung;
      end;

    SetLength(Pal.TAdresse, Length(TCodeB));
    for I := 0 to Length(TCodeB) - 1 do
      begin
        Pal.TAdresse[I].Wort := TCodeB[I + 1].Wort;
        Pal.TAdresse[I].Bezeichnung := TCodeB[I + 1].Bezeichnung;
      end;
  end;
  MyObjects.Add(Din);
  MyObjects.Add(Pal);
end;

himitsu 8. Sep 2024 16:07

AW: Sortieren eines Array of record
 
Das wurde doch gezeigt?

Es gibt eine Sortierfunktion,
der gibt man einfach sein Array rein
und dann muß man noch irgendwie eine Vergleichsfunktion (Interface) reingeben.

Ohne Comparer wird womöglich falsch sortiert verglichen. (ohne passenden Default-Comparer wird einfach binär verglichen)
Für einfache Typen, wie Integer oder Strings, gibt es einen Default-Comparer ... für den Rest muß man selbst was generieren/übergeben.
https://docwiki.embarcadero.com/Libr...ns.TArray.Sort
https://docwiki.embarcadero.com/Libr...ults.IComparer
https://www.delphipraxis.net/191252-...sortieren.html
...

Es gibt 2 Comparer-Interfaces, einmal ala SameText, mit Boolean-Result und eben ala CompareText, mit -1, 0 oder +1 aka Kleiner, Gleich oder Größer, als Result.
Wenn Funktionen die passende Signatur (Paramerter) besitzen, wie z.B. CompareText, CompareStr, AnsiCompareStr mit 2 Parametern, dann können sie "direkt" genommen werden.

Man baut sich also ein Objekt+Interface oder packt einfach nur eine Methode in ein Delegator-Interface.

Bei mehr als einem Feld in Records, wird das einfach verschachtelt.
Delphi-Quellcode:
function(const Left, Right: TMyRecord): Integer
begin
  Result := ComareText(Left.Feld1, Right.Feld1);
  if Result = 0 then
    Result := ComareText(Left.Feld2, Right.Feld2);
  if Result = 0 then
    Result := ComareText(Left.Feld3, Right.Feld3);
  ...
end
In der Unit Math existieren auch Delphi-Referenz durchsuchenCompareValue für Zahlen, aber man kann es auch selbst machen.
Delphi-Quellcode:
Result := ComareXXXXX(Left.Feld1, Right.Feld1);
// ala
if Left.Feld1 < Right.Feld1 then
  Result := -1
else if Left.Feld1 = Right.Feld1 then
  Result := 0
else {if Left.Feld1 > Right.Feld1 then}
  Result := +1;


Ich bin mir sicher, dass es selbst für Delphi fertige Komponenten für G-Code existieren.

ebi 8. Sep 2024 16:16

AW: Sortieren eines Array of record
 
Hallo,

bitte um Verständnis der Profis.

Mein neuer Delphi-CODE

Delphi-Quellcode:
FUNCTION TCodeSorted(Value: array of TCode): TArray<TCode>;
begin
  SetLength(Result, Length(Value));
  for var I := 0 to Length(Result) - 1 do
    Result[I] := Value[Low(Value) + I];
  TArray.Sort<TCode>(Result, TDelegatedComparer<TCode>.Create(
    FUNCTION(const Left, Right: TCode): integer
    begin
      Result := string.Compare(Left.Wort, Right.Wort, [coDigitAsNumbers]);
    end));
end;




    SetLength(TArray, Length(GCodeB));
    Zaehler := 0;

    var
    arr := TCodeSorted(GCodeB);
    for var rec in arr do
      begin
        TArray[Zaehler].Wort := rec.Wort;
        TArray[Zaehler].Bezeichnung := rec.Bezeichnung;
        Inc(Zaehler);
      end;

    SetLength(Pal.Wegbedingung, Length(TArray));
    for I := 0 to Length(TArray) - 1 do
      begin
        Pal.Wegbedingung[I].Wort := TArray[I].Wort;
        Pal.Wegbedingung[I].Bezeichnung := TArray[I].Bezeichnung;
      end;

himitsu 8. Sep 2024 16:29

AW: Sortieren eines Array of record
 
+1?
und Low+1 aka 0+1 aka immer 1?

[edit] AAAAAAHH, I nicht 1 ... schwer zu erkennen. PS: Darum verwende ich immer nur das keine i, auch wenn ich alle anderen einbuchstabigen Variablen ebenfalls groß schreibe.
Delphi-Quellcode:
for var I := 0 to High(Result) do
  Result[I] := Value[I];
Delphi-Quellcode:
param: array of ...
sollte immer mit 0 beginnen, egal was reingegeben wurde. :gruebel:



warum nicht?
Delphi-Quellcode:
FUNCTION TCodeSorted(Value: TArray<TCode>): TArray<TCode>;
begin
  Result := Value;
oder direkt
Delphi-Quellcode:
procedure TCodeSorted(var Value: TArray<TCode>);
begin
[edit] Ahhh OK, die statischen Arrays.
Wobei man es inzwischen auch direkt dynamische Konstanten und Variablen deklarieren kann.
Delphi-Quellcode:
const // oder var
  GCodeB: array of TCode = [
    ...
  ];



Wenn "Wort" nicht eindeutig ist und somit auch noch nach Bezeichnung sortiert werden müsste.
Delphi-Quellcode:
    begin
      Result := string.Compare(Left.Wort, Right.Wort, [coDigitAsNumbers]);
      if Result = 0 then
        Result := string.Compare(Left.Bezeichnung, Right.Bezeichnung, [coDigitAsNumbers]);
    end));

ebi 8. Sep 2024 16:37

AW: Sortieren eines Array of record
 
hallo himitsu,

vielen Dank, ich werde versuchen Dein Delphi-CODE zu erlernen.

HG

himitsu 8. Sep 2024 16:48

AW: Sortieren eines Array of record
 
Das "Warum" ignorieren ... hab ich oben editiert/geändert.

Aber bei dem +1 weist du ja immer das zweite Array-Item deinem Result zu.
Tipp: mit dem Debugger mal ansehen, was in der Result-Variable nach deiner Schleife drin steht.





Schön ist es auch, wenn man Gleiches Zusammengehöriges zusammenfasst.
So kann z.B. der Record selbst seine eigene Sortierfunktion bereitstellen.

Delphi-Quellcode:
type
  TCode = record
    Wort: string;
    Bezeichnung: string;
    class function Compare(const Left, Right: TCode): Integer; static;
  end;

// das Class+Static ist dafür, damit es kein implizites SELF gibt (als ersten unsichtbaren Parameter), also genauso, als wäre die Methode nicht in einer Klasse/Record.
class function TCode.Compare(const Left, Right: TCode): Integer;
begin
  Result := string.Compare(Left.Wort, Right.Wort, [coDigitAsNumbers]);
end;


TArray.Sort<TCode>(Self.TAdresse, TDelegatedComparer<TCode>.Create(TCode.Compare));


PS: Der Name mit T ist schon ein bissl verwirrend ... klingt irgendwie nicht nach Feld/Variable, sondern mehr nach Typ/Klasse.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:39 Uhr.
Seite 1 von 3  1 23      

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 by Thomas Breitkreuz