Eingebung Übergabe dynamischer Liste

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
TroaX
Beiträge: 684
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Linux Mint | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Linux Mint
Wohnort: NRW
Kontaktdaten:

Eingebung Übergabe dynamischer Liste

Beitrag von TroaX »

Ich benötige mal eine kleine Eingebung. Ich will jetzt mal wieder ein Projekt erarbeiten. Die Brigitte hatte mich mit ihrem Thread auf eine Idee gebracht und da wir auf Arbeit da sowieso ein kleines Problem haben, wollte ich das gerne lösen. Die Idee ist ein Programm, in dem ich zum einen Formulare mit Hilfe der Dialog-Bibliothek generiere, die am Ende aber eben auch gleichzeitig eine HTML-Vorlage mit Daten füttert. Also man wählt eine Vorlage aus, bekommt dafür das passende Formular, das füllt man dann aus und das Programm generiert dafür das fertige Dokument wiederum aus einer HTML-Vorlage. Aber um das Thema Dialog geht das noch nicht. Da ich mit dem Thema Erfahrung habe, wollte ich erst einmal die Templateengine (so nennt sich das bei uns im PHP-Universum) implementieren. Ist ja auch nicht schwer. Nun ist php nun einmal dynamisch typisiert und man kann da alles mit allem mischen. In Purebasic nicht.

Wie übergebe ich am sinnvollsten eine dynamisch große Liste, die wiederum nicht spezifizierte Felder enthält? Das einzig spezifische ist der Datentyp, der logischerweise String sein sollte. Aber wie macht man das am schlauesten? Denn im Grunde gibt es 2 Ebenen. Die erste Ebene ist eine Linked List. Denn es ist ja nie fest, wie viele Elemente reinkommen. Die zweite Ebene ist jetzt aber die große Frage. Eine Liste mit Strukturen wäre am logischsten. Aber wie kann ich mit Hilfe eines Strings auf ein Element der Struktur zugreifen? Die zweite Möglichkeit wäre eine Map. Da wäre das Zugriffsproblem gelöst. Nur da muss dann eben auch wieder eine Struktur zwischen, da es den Datentyp Map für eine Linked List nicht gibt. Das ist aber blöd zu händeln.

Hat da jemand eine Idee?

Mein bisheriges Modul:

Code: Alles auswählen

EnableExplicit

; Replacer-Moldule for Replacing Placeholder in Plaintext, HTML, Markdown etc.

; ===================================
; Module Declaration for external Use
DeclareModule Replacer
  Declare.s ReplaceVariable(template.s, variable.s, content.s)
  Declare.s ReplaceCondition(template.s, conditionblock.s, condition.b)
  ; Hier muss noch die Loop-Prozedur hin
EndDeclareModule

; ====================
; Moduleimplementation
Module Replacer
  ; ==================
  ; Internal variables
  Define ExpressionVariable.s
  Define ExpressionLoop.s
  Define ExpressionEntity.s
  Define ExpressionCondition.s
  Define ExpressionFlags.i
  
  ExpressionVariable = "{%VAR:<NAME>}"
  ExpressionLoop = "{%LOOP:<NAME>}(.*?){%ENDLOOP:<NAME>}"
  ExpressionEntity = "{%ENT:<NAME>}"
  ExpressionCondition = "{%IF:<NAME>}(.*?){%ENDIF:<NAME>}"
  ExpressionFlags = #PB_RegularExpression_DotAll | #PB_RegularExpression_MultiLine | #PB_RegularExpression_AnyNewLine | #PB_RegularExpression_NoCase
  
  ; ========================================
  ; Procedure to Replace any single variable
  Procedure.s ReplaceVariable(template.s, variable.s, content.s)
    Shared ExpressionVariable
    
    ExpressionVariable = ReplaceString(ExpressionVariable,"<NAME>",variable)
    
    ProcedureReturn ReplaceString(template,ExpressionVariable,content) 
  EndProcedure
  
  ; ==========================================================
  ; Procedure to show or delete textblock by a given condition
  Procedure.s ReplaceCondition(template.s, conditionblock.s, condition.b)
    Shared ExpressionCondition
    Shared ExpressionFlags
    Define Expression.i
    Define Replacement.s
    
    ExpressionCondition = ReplaceString(ExpressionCondition, "<NAME>", conditionblock)
    
    Expression = CreateRegularExpression(#PB_Any, ExpressionCondition, ExpressionFlags)
    If ExamineRegularExpression(Expression, template)
      While NextRegularExpressionMatch(Expression)
        If condition
          template = ReplaceString(template, RegularExpressionMatchString(Expression), RegularExpressionGroup(Expression,1))
        Else
          template = ReplaceString(template, RegularExpressionMatchString(Expression), "")
        EndIf
      Wend 
    EndIf
    
    FreeRegularExpression(Expression)
    
    ProcedureReturn template
  EndProcedure
  
  ; =================================================================
  ; Procedure to repeating a textblock and replace entity placeholder
  Procedure.s ReplaceLoop(template.s, variable.s, ; BLOCKADE!)
    ; Und wie weiter?
    ; Hier soll der Textclock, der mit {%LOOP:<NAME>}TEXTBLOCK{%ENDLOOP:<NAME>} umschlossen
    ; so lange wiederholt werden, bie alle Zeile einer Liste abgearbeitet und die Einträge
    ; innerhalb des Blockes ersetzt wurde.
    ; Da es aber so dynamisch wie möglich sein soll, benötige eine Eingebung bzgl. des Parameters.
EndModule
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Linux Mint
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Linux Mint
NAS: Fritz.Box 5690 Pro (Nur für Keepass-DB)
Coding: Purebasic, Spiderbasic, GDevelop, Javascript/Node
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Eingebung Übergabe dynamischer Liste

Beitrag von STARGÅTE »

So ganz habe ich nicht verstanden wo du hin willst, aber bei "da es den Datentyp Map für eine Linked List nicht gibt" muss ich widersprechen.
Du kannst der Liste ja einfach eine Struktur geben die eine Map enthält.
Wenn die sich auch noch sich selbst definiert, ist ein unbegrenzter Struktur-Feld-Baum möglich:

Code: Alles auswählen

Structure MyStructure
	Map Field.MyStructure()
	Value.s
EndStructure

Procedure ShowStructure(*MyStructure.MyStructure, Depth=0)
	ForEach *MyStructure\Field()
		If MapSize(*MyStructure\Field()\Field())
			Debug Space(Depth*3) + MapKey(*MyStructure\Field()) + " {"
			ShowStructure(*MyStructure\Field(), Depth+1)
			Debug Space(Depth*3) + "}"
		Else
			Debug Space(Depth*3) + MapKey(*MyStructure\Field()) + " = " + *MyStructure\Field()\Value
		EndIf
	Next
EndProcedure

Procedure Evaluate(List MyList.MyStructure())
	ForEach MyList()
		ShowStructure(MyList())
	Next
EndProcedure


Define NewList MyList.MyStructure()

AddElement(MyList())

MyList()\Field("AnyName")\Field("AnyOtherName")\Value = "Hello World!"
MyList()\Field("AnyName")\Field("SomeOtherName")\Value = "Foo Bar"
MyList()\Field("SomeName")\Value = "Blub"

Evaluate(MyList())
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
TroaX
Beiträge: 684
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Linux Mint | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Linux Mint
Wohnort: NRW
Kontaktdaten:

Re: Eingebung Übergabe dynamischer Liste

Beitrag von TroaX »

Genau das steht doch schon im selben Satz
Nur da muss dann eben auch wieder eine Struktur zwischen, da es den Datentyp Map für eine Linked List nicht gibt.
Dein Beispiel tut genau das. Es setzt eine Struktur mit einem Element des Typs Map als Typ für die Linked List ein, weil Map direkt nicht als Typ für eine Linked List genutzt werden kann.

Eine Linked List funktioniert nur mit einem skalaren Datentypen oder einer Struktur als Typ. Gebe ich einer Liste ein Array, eine Map oder eine andere Liste als Typ, macht der Compiler den Popo hoch.

Ich habe nur gehofft, das jemand die Eingebung zu einer alternativen Herangehensweise hat. Ich bin schon die ganze Zeit dabei, mit Macros etwas zurecht zu tüfteln. Aber so wirklich fruchtbar sind die Versuche nicht. Auch das Modul wieder als eine Art statische Klasse zu verwenden und Getter/Setter Prozeduren für die Bindung der Daten zu an das Modul zu implementieren, blähen mir am Ende den Anwendungscode unnötig auf.

Wenn es keine Alternative für das Verschachteln von Listen mit Maps gibt, dann mach ich das so. Aber ich habe noch Hoffnung, das es da noch eine elegantere Lösung gibt als das. Mir wäre eine eine Linked List mit der fertigen Struktur lieber. ;)
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Linux Mint
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Linux Mint
NAS: Fritz.Box 5690 Pro (Nur für Keepass-DB)
Coding: Purebasic, Spiderbasic, GDevelop, Javascript/Node
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Eingebung Übergabe dynamischer Liste

Beitrag von STARGÅTE »

TroaX hat geschrieben: 19.11.2023 12:13 Genau das steht doch schon im selben Satz
Nur da muss dann eben auch wieder eine Struktur zwischen, da es den Datentyp Map für eine Linked List nicht gibt.
Dein Beispiel tut genau das. Es setzt eine Struktur mit einem Element des Typs Map als Typ für die Linked List ein, weil Map direkt nicht als Typ für eine Linked List genutzt werden kann.
Hm ja gut. Klar ist da n Struktur drin, aber das ist nun mal die Art wie PB damit umgeht. Aber wo ist das Problem?
Wolltest du sowas hier machen:

Code: Alles auswählen

Define NewList NewMap MyMapAsList.s()()

AddElement(MyMapAsList())
MyMapAsList()("Beispiel") = "Element"
Aber das ist ja wiederum nicht dynamisch, weil dann ja die Map-Element wieder String sind und nicht dynamisch tiefer gehen.
STARGÅTE hat geschrieben: 19.11.2023 11:39 Mir wäre eine eine Linked List mit der fertigen Struktur lieber.
Ähh, jetzt doch wieder Struktur!?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
TroaX
Beiträge: 684
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Linux Mint | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Linux Mint
Wohnort: NRW
Kontaktdaten:

Re: Eingebung Übergabe dynamischer Liste

Beitrag von TroaX »

Wieder Zitat aus meinem ersten Post:
Eine Liste mit Strukturen wäre am logischsten. Aber wie kann ich mit Hilfe eines Strings auf ein Element der Struktur zugreifen?
Das ist mein Problem! Denn das geht ohne Tricks nicht (Wenn es denn einen gäbe. Deswegen frage ich), wäre aber eleganter. Mit Makros bekomme ich es nicht hin. Aber vielleicht hat da ja wer nen Tip.
Die zweite Möglichkeit wäre eine Map. Da wäre das Zugriffsproblem gelöst. Nur da muss dann eben auch wieder eine Struktur zwischen, da es den Datentyp Map für eine Linked List nicht gibt. Das ist aber blöd zu händeln.
Das ist dein Vorschlag. Ist aber weniger elegant. Und ich habe gehofft, das wenn hier schon versucht wird, Purebasic OOP beizubringen, das jemand vielleicht einen Macro-Hack oder ähnliches hat, der das lösen könnte.

Aber ich habe schon selbst jetzt einiges in Macros probiert und festgestellt, das man damit keinen String so ummünzen kann, das dieser als Bezeichnung eines Strukturelements verwendet werden kann. War auch ne dumme Idee. Findet ja keine Auswertung statt und dementsprechend wird auch kein String aus einer Variable an den Körper des Makros übergeben. Da gab es leider einen Denkfehler meinerseits.

Ich lese mir aber jetzt nochmal meinen Eingangspost durch. Anscheinend ist er unverständlich.
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Linux Mint
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Linux Mint
NAS: Fritz.Box 5690 Pro (Nur für Keepass-DB)
Coding: Purebasic, Spiderbasic, GDevelop, Javascript/Node
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Eingebung Übergabe dynamischer Liste

Beitrag von mk-soft »

Ein DataSet. Mischung aus List und Maps

Update

Code: Alles auswählen


Structure udtValue
  Type.w
  StructureUnion
    iVal.i
    fltVal.f
    dblVal.d
  EndStructureUnion
  strVal.s
  Map SubValue.udtValue()
EndStructure

Structure udtDataSet
  ObjectName.s
  Map Value.udtValue()
EndStructure

Global NewList DataSet.udtDataSet()

AddElement(DataSet())
With DataSet()
  \ObjectName = "Date Value 1"
  \Value("Data 1")\strVal = "Data 1"
  \Value()\SubValue("x")\strVal = "100"
  \Value()\SubValue("y")\strVal = "200"
  \Value("Data 2")\strVal = "Data 2"
  \Value()\SubValue("x")\strVal = "300"
  \Value()\SubValue("y")\strVal = "400"
EndWith

AddElement(DataSet())
With DataSet()
  \ObjectName = "Date Value 2"
  \Value("Name 1")\strVal = "Tom"
  \Value()\SubValue("Age")\strVal = "30"
  \Value("Name 2")\strVal = "Jerry"
  \Value()\SubValue("Age")\strVal = "35"
  \Value()\SubValue("Size")\strVal = "70"
EndWith

ForEach DataSet()
  Debug "ObjectName:" + DataSet()\ObjectName
  ForEach DataSet()\Value()
    Debug MapKey(DataSet()\Value()) + " = " + DataSet()\Value()\strVal
    ForEach DataSet()\Value()\SubValue()
      Debug MapKey(DataSet()\Value()) + "\" + MapKey(DataSet()\Value()\SubValue())  + " = " + DataSet()\Value()\SubValue()\strVal
    Next
  Next
Next
Zuletzt geändert von mk-soft am 19.11.2023 13:49, insgesamt 1-mal geändert.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Eingebung Übergabe dynamischer Liste

Beitrag von STARGÅTE »

mk-soft hat geschrieben: 19.11.2023 13:18 Ein DataSet. Mischung aus List und Maps
Ganau das habe ich ja hier vorgeschlagen.

Aber wenn ich TroaX jetzt richtig verstehe will ehr sowas hier:

Code: Alles auswählen

Structure MyStructure
	Float.f
	String.s
	Integer.i
EndStructure

Define MyStructure.MyStructure

MyStructure\Float = 3.14

Define Field.s = "Float"

Debug MyStructure\{Field} ; {Field} wird zu Float
Aber wie TroaX schon selber schrieb, funktioniert das natürlich nicht, weil Strings ja erst zur Laufzeit existieren.

Man könnte aber die Runtime Library aufmotzen und sowas dann ermöglichen:

Code: Alles auswählen

Runtime Structure MyStructure
	Float.f
	String.s
	Integer.i
EndStructure

Define MyStructure.MyStructure
Runtime MyStructure

MyStructure\Float = 3.14

Debug GetRuntimeFloat("MyStructure", "Float") ; Das würde dann nach MyStructure\Float aufgelöst werden
@TroaX: Bin ich jetzt auf dem richtigen Weg?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Eingebung Übergabe dynamischer Liste

Beitrag von mk-soft »

Haben noch einmal etwas angepasst. siehe oben
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
TroaX
Beiträge: 684
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Linux Mint | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Linux Mint
Wohnort: NRW
Kontaktdaten:

Re: Eingebung Übergabe dynamischer Liste

Beitrag von TroaX »

Vielen Dank :allright:

Aber das Thema hat sich erledigt. Ich habe es nicht geschafft, meine Intention vernünftig zu kommunizieren. Ich scheine schon völlig unter "Social Media Weakness" zu leiden. Aber ja. Ich habe mich nicht richtig ausgedrückt. Das war mein Fehler! :oops:

Mir ging es eigentlich um einen Hack, der es ermöglichen sollte, Nutzer eines Moduls eine logischere und elegantere Art der Listenerzeugung zu ermöglichen, um eben ohne das Verschachteln von Listen und Maps zu arbeiten, welches einem eine weitere Struktur dazwischen aufzwingt. Also im Grunde eine LinkedList vom Typ Struktur und fertig. Das wäre zum Beispiel möglich, in dem man mit einem String auf den Bezeichner eines Strukturelements zugreifen könnte. Das geht aber nicht und ich hatte die Hoffnung, das es da ein Hack z.B. mit Macros gibt. Dann fiel mir aber eben ein, das sich dieses vorgehen wieder mit der Idee beißt, das man für das spätere fertige Programm ja auch dynamisch viele Elemente in der zweiten Ebene brauch. Und dafür taugen wiederum die Strukturen nicht. Und das weg zu abstrahieren bringt nichts, weil die Liste selber ja trotzdem komplett mit Struktur angelegt werden muss. Und dann kann ich mir das ganze auch komplett sparen.

Die Idee war eigentlich:

Code: Alles auswählen

Structure teststruct
  TestFieldA.s
  TestFieldB.s
  TestFieldC.s
EndStructure

NewList FieldTest.teststruct()
AddElement(FieldTest())
FieldTest()\TestFieldA = "A1"
FieldTest()\TestFieldB = "A2"
FieldTest()\TestFieldC = "A3"
AddElement(FieldTest())
FieldTest()\TestFieldA = "B1"
FieldTest()\TestFieldB = "B2"
FieldTest()\TestFieldC = "B3"
AddElement(FieldTest())
FieldTest()\TestFieldA = "C1"
FieldTest()\TestFieldB = "C2"
FieldTest()\TestFieldC = "C3"

SelectElement(FieldTest(), 1)

; Und folgende geht natürlich nicht!
FieldTest()\"TestFieldB"

; Und das hier auch nicht!
StringTest.s = "TestFieldB"
FieldTest()\StringTest

; Und ich dachte man könnte das ja mit einem Hack z.B. über Macros lösen
War aber eine Schnapsidee.

Sorry, falls ich jemanden Zeit verschwendet habe. Nichts für ungut. Ich ärgere mich gerade selbst über mich. :angry:
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Linux Mint
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Linux Mint
NAS: Fritz.Box 5690 Pro (Nur für Keepass-DB)
Coding: Purebasic, Spiderbasic, GDevelop, Javascript/Node
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Eingebung Übergabe dynamischer Liste

Beitrag von mk-soft »

Code: Alles auswählen

Structure teststruct
  Map Field.s()
EndStructure

NewList FieldTest.teststruct()
AddElement(FieldTest())
FieldTest()\Field("TestFieldA") = "A1"
FieldTest()\Field("TestFieldB") = "A2"
FieldTest()\Field("TestFieldC") = "A3"
AddElement(FieldTest())
FieldTest()\Field("TestFieldA") = "B1"
FieldTest()\Field("TestFieldB") = "B2"
FieldTest()\Field("TestFieldC") = "B3"
AddElement(FieldTest())
FieldTest()\Field("TestFieldA") = "C1"
FieldTest()\Field("TestFieldB") = "C2"
FieldTest()\Field("TestFieldC") = "C3"

SelectElement(FieldTest(), 1)

Debug FieldTest()\Field("TestFieldB")

StringTest.s = "TestFieldC"
Debug FieldTest()\Field(StringTest)

Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten