Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Integer in Set laden (https://www.delphipraxis.net/202288-integer-set-laden.html)

DieDolly 16. Okt 2019 16:36

Integer in Set laden
 
Ich habe diese Deklarationen
Delphi-Quellcode:
type
 TNiveau = (nA = 1, nB = 2, nC = 4, nC = 8, nD = 16, nE = 32);
 TNiveauSet = set of TNiveau;
In einer Procedure lade ich einen Integerwert aus einer Datei der zum Beispiel 57 sein kann in eine Variable NiveauInt.
Mit sowas hier gucke ich, welches Niveau im Set enthalten ist (insgesamt 6x)
Delphi-Quellcode:
if TNiveau.nA in NiveauInt then
 Include(NiveauSet, TNiveau.nA);
Das Problem ist, dass ich die 57 nicht in die Variable NiveauInt geladen bekomme.
Mein Versuch
Delphi-Quellcode:
NiveauInt := TNiveauSet(Byte(57));
Egal von welchem Typ NiveauInt ist, es klappt nicht. Was mache ich falsch?

Uwe Raabe 16. Okt 2019 16:40

AW: Integer in Set laden
 
Der höchste Wert im Set is 32. Damit benötigt das Set 33 Bit und passt nicht mehr in einen Integer - und schon gar nicht in ein Byte.

DieDolly 16. Okt 2019 16:49

AW: Integer in Set laden
 
Habe ich hier einen Denkfehler? Int64 funktioniert auch nicht.
Das Problem ist, dass ich = 1, = 2, = 4 bis 32 angeben muss, da die Werte die von Außen kommen sonst nicht stimmen.

Delphi-Quellcode:
 NiveauInt := TNiveauSet(StrToInt64Def(57, 0));

Redeemer 16. Okt 2019 16:58

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449788)
Delphi-Quellcode:
 NiveauInt := TNiveauSet(StrToInt64Def(57, 0));

Na ja, 57 ist auch kein String, falls du das meinst.

DieDolly 16. Okt 2019 16:59

AW: Integer in Set laden
 
Ist nur ein Tippfehler hier im Editor von mir. Da kommt schon ein String rein.

Uwe Raabe 16. Okt 2019 17:05

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449788)
Habe ich hier einen Denkfehler?

Vermutlich! Dein Code compiliert ja nicht mal, da nC doppelt vorkommt. Also zeig bitte mal den realen Code.

DieDolly 16. Okt 2019 17:21

AW: Integer in Set laden
 
Nimm das nC weg :P Es sind nur Tippfehler im Editor. Das ist so gesehen realer Code nur habe ich die Variablennamen abgeändert. Alle Namen der Deklarationen sind bei mir richtig.
Sowas würde der Compiler als aller erstes bemängeln. Aber es geht nur um diese Umwandlung. Es hakt nur an dieser einen Stelle

Delphi-Quellcode:
NiveauInt := TNiveauSet(StrToInt64Def('57', 0));
Die 57 kommt aus einer Textdatei.

Auch hiermit kommt der Umwandlungsfehler. Also ohne Zuweisungen der Zahlen.
Delphi-Quellcode:
  TNiveau = (nA, nB, nC, nD, nE, nF);
Füge ich dann oben Byte() hinzu, funktioniert es. Aber ich brauche leider die Wert bis = 32.

Ich erkläre mal das Vorhaben.
Ein externes Programm hat 6 Niveau-Stufen die man freischalten kann. Das Programm speichert das in folgenden Schritten: 1, 2, 4, 8, 16 und 32.
Hat man alle 6 Stufen freigeschaltet, steht in der Konfigurationsdatei 63.

Diese Zahl lese ich aus und möchte meine Datentypen oben damit korrekt füllen. Das mache ich mit den
Delphi-Quellcode:
in
-Abfragen.

DenkDirNix 16. Okt 2019 17:45

AW: Integer in Set laden
 
Wenn solche Typ-Umwandlungen haken kann man gut mit varianten Records "herumspielen". In deinem Fall:

Code:
var
  Niveau: case boolean of
            false: (Menge: TNiveauSet);
            true : (Int : int64)
          end

Uwe Raabe 16. Okt 2019 17:48

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449795)
Füge ich dann oben Byte() hinzu, funktioniert es. Aber ich brauche leider die Wert bis = 32.

Brauchst du nicht! Denn...

Zitat:

Zitat von DieDolly (Beitrag 1449795)
Ein externes Programm hat 6 Niveau-Stufen die man freischalten kann. Das Programm speichert das in folgenden Schritten: 1, 2, 4, 8, 16 und 32.
Hat man alle 6 Stufen freigeschaltet, steht in der Konfigurationsdatei 63.

Die Zahlen 1, 2, 4, 8, 16, 32 sind lediglich die entsprechenden Bitmasken, aber nicht die Ordnungszahlen der Set-Elemente.

Da deine Integerwerte nicht größer als 63 werden können, genügt ein Byte-Cast.

Direkt auf den Integer casten geht nicht, da das Set nur ein Byte groß ist und somit beim Cast auf einen Integer die Größe nicht passt.

samso 16. Okt 2019 17:57

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449795)
Das Programm speichert das in folgenden Schritten: 1, 2, 4, 8, 16 und 32.
Hat man alle 6 Stufen freigeschaltet, steht in der Konfigurationsdatei 63.

Dann hat Dein Set aber nicht 33 Bit sondern 6 Bit. So sollte es gehen:

Delphi-Quellcode:
type
 TNiveau = (nA, nB, nC, nD, nE, nF);
 TNiveauSet = set of TNiveau;


var
  Niveaus: TNiveauSet;
  NiveauZahl: Byte;
begin
  Niveaus := TNiveauSet(Byte(StrToInt('57')));
  NiveauZahl := Byte(Niveaus);
end;

DieDolly 16. Okt 2019 18:18

AW: Integer in Set laden
 
Wenn ins Programm 57 eingelesen wird, wie ermittle ich dann welche Niveaus freigeschaltet wurden bei nur 6 Bit?

Das externe programm speichert Niveau 1 mit 1 ab, 2 mit 2, 3 mit 4, 4 mit 8, 5 mit 16 und 6 mit 32.

samso 16. Okt 2019 18:30

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449807)
Wenn ins Programm 57 eingelesen wird, wie ermittle ich dann welche Niveaus freigeschaltet wurden bei nur 6 Bit?

Das externe Programm speichert Niveau 1 mit 1 ab, 2 mit 2, 3 mit 4, 4 mit 8, 5 mit 16 und 6 mit 32.

Ja, und Du speicherst Niveau 1 mit nA ab, 2 mit nB, 3 mit nC, 4 mit nD, 5 mit nE und 6 mit nF. Sind alle Niveaus von 1 bis 32 freigeschaltet, ist auch nA bis nF gesetzt. Liest Du 57 ein, ist Dein Set: [nA, nD, nE, nF].

Wenn Du wissen willst, ob Niveau 5 freigeschaltet ist, dann ist die Abfrage dazu
Code:
nE in Niveaus
Hast Du meinen Quelltext mal ausprobiert?

Vielleicht ist es so klarer:

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
 TNiveau = (Niveau1, Niveau2, Niveau3, Niveau4, Niveau5, Niveau6);
 TNiveauSet = set of TNiveau;


var
  Niveaus: TNiveauSet;
  NiveauZahl: Byte;
begin
  Niveaus := TNiveauSet(Byte(StrToInt('57')));
  NiveauZahl := Byte(Niveaus);
  if Niveau5 in Niveaus then
    WriteLn('Niveau 5 ist freigeschaltet');
end.

DieDolly 16. Okt 2019 18:38

AW: Integer in Set laden
 
Ich glaube du hast mich nicht verstanden.
Ich speichere gar nix ab. Ich lese nur aus.

Das andere Programm speichert ab mit 1 2 4 8 16 32 und allen Kombinationen daraus. Da kann ich nix dran ändern. Und das muss ich auslesen.

Und da das hier nicht funktioniert bin ich aufgeschmissen
Delphi-Quellcode:
TNiveau = (nA = 1, nB = 2, nC = 4, nD = 8, nE = 16, nF = 32);
TNiveauSet = set of TNiveau;

NiveauInt := TNiveauSet(StrToInt64Def(<der wert der von draußen kommt>, 0));

Uwe Raabe 16. Okt 2019 18:45

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449809)
Ich glaube du hast mich nicht verstanden.

Ich fürchte, du verstehst uns nicht. Deine Vorstellung der Bedeutung der Zahlwerte ist schlichtweg falsch.

samso 16. Okt 2019 18:50

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449809)
Ich speichere gar nix ab.

Ich meinte diesen Vorgang
Code:
NiveauInt := <irgendwas>
Da wird in der Variablen NiveauInt etwas gespeichert. Bei meinem Programm wird in der Variablen "Niveaus" ebenfalls etwas gespeichert.

DieDolly 16. Okt 2019 18:57

AW: Integer in Set laden
 
Dann verstehe ich euch tatsächlich nicht und verstehe auch grundsätzlich überhaupt nix mehr.

Wenn ich von Außen 57 lese dann bedeutet das Niveau 1, 4, 5 und 6 sind frei. 2 und 3 noch nicht.
Wie gestaltet sich dann die Abfrage?
Delphi-Quellcode:
if TNiveau.nB in NiveauInt then // das hier dürfe niemals zutreffen, da Niveau 2 (B) nicht freigeschaltet ist.
 Include(NiveauSet, TNiveau.nB);
Aber da oben wird doch im Prinzip geprüft, ob die 1 in der 57 ist. Denn Element nB ist das zweite Element im Set mit dem Wert 1.
Aber eigentlich müsste ich 2 abfragen.

Ok ich glaube das wars ich gebe auf. Ich brauche diese Zahlen weil ich sonst keine Ahnung habe wie ich prüfen kann was frei ist und was nicht.

samso 16. Okt 2019 19:10

AW: Integer in Set laden
 
Ich kann mich nur wiederholen. Mein Programm leistet exakt das, was Du möchtest. Teste es doch bitte bitte bitte mal!

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
 TNiveau = (Niveau1, Niveau2, Niveau3, Niveau4, Niveau5, Niveau6);
 TNiveauSet = set of TNiveau;

var
  Niveaus: TNiveauSet;
  N: TNiveau;
begin
  Niveaus := TNiveauSet(Byte(StrToInt('57'))); // Integer in das Set laden
  // Ausgabe welche Niveaus freigeschaltet sind
  for N:=Niveau1 to Niveau6 do
  begin
    if N in Niveaus then
      WriteLn(Format('Niveau %d ist freigeschaltet', [ord(N)+1]));
  end;
  ReadLn;
end.

p80286 16. Okt 2019 19:13

AW: Integer in Set laden
 
Warum machst Du es nicht nach alter Väter Sitte
Delphi-Quellcode:
funktion Bit0set(wert:byte)_boolean;
begin
result:=((wert and 1) =1);
end;

funktion Bit1set(wert:byte):boolean;
begin
result:=((wert and 2) =2);
end;

usw.
Gruß
K-H

Uwe Raabe 16. Okt 2019 19:14

AW: Integer in Set laden
 
Zitat:

Zitat von p80286 (Beitrag 1449814)
Warum machst Du es nicht nach alter Väter Sitte

Ich hatte schon auf so was gewartet...

samso 16. Okt 2019 19:22

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449812)
Dann verstehe ich euch tatsächlich nicht und verstehe auch grundsätzlich überhaupt nix mehr.

Wenn ich von Außen 57 lese dann bedeutet das Niveau 1, 4, 5 und 6 sind frei. 2 und 3 noch nicht.
Wie gestaltet sich dann die Abfrage?
Delphi-Quellcode:
if TNiveau.nB in NiveauInt then // das hier dürfe niemals zutreffen, da Niveau 2 (B) nicht freigeschaltet ist.
 Include(NiveauSet, TNiveau.nB);
Aber da oben wird doch im Prinzip geprüft, ob die 1 in der 57 ist. Denn Element nB ist das zweite Element im Set mit dem Wert 1.
Aber eigentlich müsste ich 2 abfragen.

Ok ich glaube das wars ich gebe auf. Ich brauche diese Zahlen weil ich sonst keine Ahnung habe wie ich prüfen kann was frei ist und was nicht.

Man kann das natürlich auch ohne Sets umsetzen. Dann bekommt man auch die 32 zu sehen...

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

var
  Niveaus: Integer;
  i: Integer;
  N: Integer;
begin
  Niveaus := StrToInt('57');
  N := 1;
  for i := 1 to 6 do
  begin
    if N and Niveaus<>0 then
      WriteLn(Format('Niveau %d ist freigeschaltet', [i]));
    N := N * 2;
  end;
  ReadLn;
end.
Gerne liefere ich das auch in Assembler...

samso 16. Okt 2019 19:35

AW: Integer in Set laden
 
Zitat:

Zitat von DieDolly (Beitrag 1449812)
Aber da oben wird doch im Prinzip geprüft, ob die 1 in der 57 ist.

Und das stimmt eben nicht! Da wird geprüft ob nB in der Menge NiveauInt enthalten ist. Hier bildet Pascal/Delphi die Mengenlehre nach.

p80286 16. Okt 2019 20:28

AW: Integer in Set laden
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1449815)
Zitat:

Zitat von p80286 (Beitrag 1449814)
Warum machst Du es nicht nach alter Väter Sitte

Ich hatte schon auf so was gewartet...

Na dann erzähl mal.
Ich hab bisher den Eindruck, daß der Einsatz eines Sets nicht eben intuitiv ist.


Gruß
K-H

Uwe Raabe 16. Okt 2019 21:21

AW: Integer in Set laden
 
Zitat:

Zitat von p80286 (Beitrag 1449820)
Ich hab bisher den Eindruck, daß der Einsatz eines Sets nicht eben intuitiv ist.

Ist er eigentlich schon - und besser lesbar auch. Wie jedes programmtechnische Konstrukt muss man es halt beherrschen. Das unterscheidet die Sets nicht von Pointern, Arrays, Records, Strings oder Klassen - von Generics, Threads und Anonymen Methoden ganz zu schweigen. Der ASM-Verweis hatte schon seine Berechtigung. Damit lässt sich all das auch nach alter Väter Sitte realisieren. Ist aber vielleicht nicht erstrebenswert.

Michael II 16. Okt 2019 22:57

AW: Integer in Set laden
 
Hallo Dolly

gib nicht auf :-D.

Die Vorschläge sind ja alle mehr als brauchbar.

Hier noch ein paar Funktionen, welche nützlich sein könnten...

allefaelle zählt alle möglichen Fälle (0..63) auf
niv_in_n prüft, ob ein Niveau im "Fall" n enthalten ist

niv_str wandelt ein Element in einen String um
nivset_str wandelt eine Menge in einen String um

Delphi-Quellcode:
uses System.TypInfo;


type
TNiveau = (nA, nB, nC, nD, nE, nF);
TNiveauSet = set of TNiveau;

function getNiveauSet( n : byte ) : TNiveauSet;
begin
 (*
  alle fälle aufzählen:
  Result := [];
  if n and 1 = 1 then Result := Result + [nA];
  if n and 2 = 2 then Result := Result + [nB];
  if n and 4 = 4 then Result := Result + [nC];
  if n and 8 = 8 then Result := Result + [nD];
  if n and 16 = 16 then Result := Result + [nE];
  if n and 32 = 32 then Result := Result + [nF];
   *)
  // oder einfacher so:
  Result := TNiveauSet( n );
end;

function niv_str( niv : TNiveau ) : string;
begin
  Result := GetEnumName(typeinfo(TNiveau),ord(niv));
end;

function nivset_str( nivset : TNiveauSet ) : string;
var niv : TNiveau;
begin
  Result := '';
  for niv := nA to nF do
    if niv in nivset then
      Result := Result + niv_str( niv ) + ' ';
end;

function niv_in_n( niv : TNiveau; n : byte ) : boolean;
begin
  Result := niv in getNiveauSet( n );
end;

function fallnummer( n : byte ) : string;
var nivset : TNiveauSet;
begin
  nivset := getNiveauSet( n );
  Result := nivset_str( nivset );
end;

function allefaelle : string;
var
  i: Integer;
  hs : string;
begin
  hs := '';
  for i := 0 to 63 do
      hs := hs + i.ToString + ' ' + fallnummer( i ) + #13#10;
  Result := hs;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  showmessage(allefaelle);
end;

samso 17. Okt 2019 07:01

AW: Integer in Set laden
 
In dem Augenblick in dem die Zahl in ein Set übertragen wurde, muss man gedanklich die Welt der Zahlen verlassen und in die Welt der Mengenlehre eintauchen. Hier wird nicht mehr mit Zahlen hantiert, sondern mit Elementbeziehungen. Das hier behandelte Beispiel ist geradezu ein Musterbeispiel für eine Menge. Die Menge der freigeschalteten Niveaus. Wenn die einzelnen Niveaus (Elemente der Menge) dann auch noch sinnvolle Namen bekommen, bildet die Programmiersprache wunderbar anschaulich ab was der Programmierer eigentlich will. Das ist dann fast schon Umgangssprache und genau das macht die Sache dann auch so sexy.

Richtig ist, dass die Zuweisung
Code:
Niveaus := TNiveauSet(Byte(StrToInt('57')));
nicht der reinen Lehre entspricht, weil diese Zuweisung implementationsabhängig ist. Sauberer wäre diese Formulierung:

Delphi-Quellcode:
function IntegerToNiveauSet(NiveauInt: Integer): NiveauSet;
var
  N: TNiveau;
  z: Integer;
begin
  z := 1;
  Result := [];
  for N := Low(TNiveau) to High(TNiveau) do
  begin
    if z and NiveauInt<>0 then
      include(Result, N);
    z := z * 2;
  end;
end;
Die Zuweisung lautet dann
Delphi-Quellcode:
Niveaus := IntegerToNiveauSet(StrToInt('57'));

Rollo62 17. Okt 2019 07:47

AW: Integer in Set laden
 
Man könnte sich alternativ auch einen NiveauSet typ anlegen, der z.B. ein Byte ist,
und dann per record helper entsprechende Zugriffsfunktionen anlegen, die das sprachlich auch sehr anschaulich macht (und eventuell noch mehr bequeme Funktionen dazunehmen).
Wenn es im Wesentlichen um die sprachliche Erkennbarkeit geht.

TiGü 17. Okt 2019 08:48

AW: Integer in Set laden
 
Wäre es nicht viel sinnvoller, nochmal über die Grundlagen von Bitfeldern/Bitmasken zu sprechen?

Denn hier hakt es gerade im Verständnis von DieDolly.

freimatz 17. Okt 2019 08:55

AW: Integer in Set laden
 
Zitat:

Zitat von samso (Beitrag 1449840)
In dem Augenblick in dem die Zahl in ein Set übertragen wurde, muss man gedanklich die Welt der Zahlen verlassen und in die Welt der Mengenlehre eintauchen. Hier wird nicht mehr mit Zahlen hantiert, sondern mit Elementbeziehungen. Das hier behandelte Beispiel ist geradezu ein Musterbeispiel für eine Menge. Die Menge der freigeschalteten Niveaus.

Ich erlaube mir da einen kleinen Einwand. Für ein Musterbeispiel einer Menge stehen die Elemente der Menge in keiner Beziehung. Hier jedoch scheinen die Elemente eine bestimmte Reihenfolge zu haben. Auch der Name "Niveau" suggeriert das.

Ansonsten :thumb:

Michael II 17. Okt 2019 10:03

AW: Integer in Set laden
 
Ich würde das auch nie mit Mengen programmieren.
Da Dolly aber Mengen verwendet, könnte es sein, dass Dolly Mengen verwenden muss.

Da Dolly eine Zahl als Input erhält, nehme ich an, dass auch die Programmierin/der Programmierer des Inputs schlicht mit Bitmasken gearbeitet hat.

Uwe Raabe 17. Okt 2019 10:38

AW: Integer in Set laden
 
Zitat:

Zitat von freimatz (Beitrag 1449848)
Für ein Musterbeispiel einer Menge stehen die Elemente der Menge in keiner Beziehung. Hier jedoch scheinen die Elemente eine bestimmte Reihenfolge zu haben. Auch der Name "Niveau" suggeriert das.

Allerdings deutet der Eingabewert 57 an, daß in diesem Fall nur die Niveaus 1, 4, 5 und 6 freigeschaltet sind. Insofern ist der Mengenansatz hier schon gerechtfertigt.

Dennis07 18. Okt 2019 12:04

AW: Integer in Set laden
 
AN dieser Stelle möchte ich noch einmal auf die CustomSets-Library auf GitHub hinweisen, die das Erstellen von Sets aus jedem beliebigen (ordinalen Typen) erlaubt.

Stevie 18. Okt 2019 12:33

AW: Integer in Set laden
 
Delphi-Quellcode:
uses
  TypInfo;

type
 TNiveau = (nA, nB, nC, nD, nE, nF);
 TNiveauSet = set of TNiveau;

var
  n: TNiveau;
  s: TNiveauSet;
begin
  Byte(s) := 57;

  for n := Low(TNiveau) to High(TNiveau) do
    if n in s then
      Write(GetEnumName(TypeInfo(TNiveau), Ord(n)), ' ');
end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:23 Uhr.

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