[ILE.RPG] Strukturauflösung

  • Allgemein

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    [ILE.RPG] Strukturauflösung

    Servus!

    Kennt wer von euch ein Video, einen Blogeintrag oder irgendwas, was eine Strukturauflösung erklärt? Also wie sich das programmiertechnisch lösen lässt?

    Kollege meinte, das sei ein grundlegendes Informatikproblem (allgemein bekannt, schon x-fach gelöst - wusste nicht, wie ich es anders nennen sollte). Nur leider finde ich zu Strukturauflösung nix gescheites.

    Und für alle, die sich nix drunter vorstellen können:
    Ein Beispiel wäre eine Artikelstückliste (In der einfachsten Form besteht ein Artikel besteht aus 2 Unterartikel, wobei einer der beiden wiederum in einem anderen Oberartikel verbaut ist. Ich will jetzt hergehen und eine Auflösung ereichen, in der mit ausgegeben wird, welche Artikel in Artikel 1 enthalten sind, und welche Untunterartikel in den Unterartikel von #1 sind (und das für alle anderen auch)

    Lg Radinator

    ~blaze~: Thema verschoben, Titel bearbeitet
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    Hi
    die Struktur würde ich Kompositum nennen, bzw. wenn es keine Leafs gibt, fällt das wohl weg und du hast kein eigenes Architekturpattern, abgesehen von der Vererbung und der IEnumerable-Implementation. Aber mir ist nicht klar, was genau du jetzt möchtest. Anhand der Erklärung wäre mir jetzt auch nicht klar, was du meinst und ich kenne den Begriff nicht.

    Viele Grüße
    ~blaze~
    nur um alle Klarheiten zu beseitigen: Artikel = A, Unterartikel = UA
    A1 = UA1 + UA2
    A2 = UA1 + UA3 + UA4
    A3 = UA2 + UA 4
    und jetzt eben rausfinden, woraus A2 besteht und wo alles UA1 drinsteckt.

    Wenn ja, dann bin ich gedanklich bei relationalen Datenmodellen, bei denen Artikel auf ihre Bestandteile per ID verweisen. Damit lassen sich solche Strukturanalysen m.E. gut durchführen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Mist...dachte nicht, dass hier jemand den C# Tag beachtet :(

    Vielleicht noch ein wenig mehr Hintergrundinfo:
    1.) Da das Ganze programmiertechnisch gelöst werden soll, ist es eigentlich egal welche Programmiersprache verwendet wird (in meinem Fall auf einem IBM System unter Verwendung von ILE.RPG). Deswegen war auch mein Grundgedanke: Es muss doch einen abstrakte Algorithmus ( am besten in Pseudocode) geben, der das Verfahren darstellt.
    2.) Das mit dem Artikel war nur ein Beispiel. Ein anders wäre folgendes:
    Gegeben sei eine Datenbank, welche pro Eintrag den Namen einer Ansicht (im folgenden Menü genannt) und den Namen eines Programms, welches sich in dem Menü befindet, enthält:
    Menü Name
    Programm
    Nummer
    Beschreibung
    MNU001
    PRG001
    1
    Programm 01
    MNU001
    PRG002
    2
    Programm 01
    MNU001
    MNU002
    3
    Menü 02
    MNU002
    PRG003
    1
    Programm 03
    MNU002
    PRG004
    2
    Programm 04

    Soll folgendes zum Ausdruck bringen: In Ansicht/Menü 01 sind zwei Programme und eine Ansicht enthalten. Bei Aufruf von Punkt 01 wird Programm 01 aufgerufen, bei Punkt #2, das Programm 02 und bei Punkt 3 wird in die Ansicht MNU002 gewechselt. Diese enthält wiederum zwei Programme (PRG003 und PRG001). Solange ich nur eine einzige Ebene habe, lässt sich das für mich noch lösen.Doch sobald ich (wie oben) auf eine zweite Ebene stoße (MNU002), steige ich nicht mehr durch.
    Falls sich jemand in RPG auskennt, kann er/sie das vielleicht nachvollziehen:
    In RPG liest man ja klassischerweise jeden Datensatz durch und falls der aktuelle nicht passt, liest man ja den nächsten (jetzt mal auf das wesentlich ohne logische Dateien und Keylists reduziert). Mein Ansatz wäre gewesen die Datenbank sequenziell zu lesen und den aktuellen Satz auszugeben. Falls im aktuellen Satz als Programm ein Menü hinterlegt ist, den aktuellen Satz speichern und alle Sätze lesen, welche als Menü Namen den Namen des "Programms" des gespeicherten Satzes enthalten. Sollte sich wieder ein Menü hinter einem Programm verstecken, den Satz speichern und mit dem Namen des Programms alle Sätze suchen. Doch leider scheitere ich immer wieder daran.

    Wenn jemand da einen Link, einen Pseudocode oder irgendwas in der Richtung hat, dann wäre ich darüber echt froh!

    Lg Radinator
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Das ist ein Baum. Jeder Eintrag in der Tabelle stellt eine Node in dem Baum dar und jede Node hat einen Verweis auf die Parent-Node.
    Ich hab da mal ein bisschen was gebastelt. Ist zwar VB, kann man aber problemlos auf andere Sprachen übertragen.

    Ich habe den Datensätzen mal eine ganz einfache Klasse gegeben, damit man damit leichter arbeiten kann:

    VB.NET-Quellcode

    1. Public Class NodeDataRow
    2. Public Property ParentMenuName As String
    3. Public Property ActionName As String
    4. Public Property SortRank As Integer
    5. Public Property Description As String
    6. End Class


    Jetzt die Baumstruktur:

    VB.NET-Quellcode

    1. Public MustInherit Class Node
    2. Public Property SourceRow As NodeDataRow
    3. Public MustOverride Sub AccumulatePrograms(Programs As List(Of ProgramNode))
    4. End Class
    5. Public Class MenuNode
    6. Inherits Node
    7. Public Property Name As String
    8. Public Property ChildNodes As New List(Of Node)
    9. Public Overrides Sub AccumulatePrograms(Programs As List(Of ProgramNode))
    10. For Each i In ChildNodes
    11. i.AccumulatePrograms(Programs)
    12. Next
    13. End Sub
    14. End Class
    15. Public Class ProgramNode
    16. Inherits Node
    17. Public Overrides Sub AccumulatePrograms(Programs As List(Of ProgramNode))
    18. Programs.Add(Me)
    19. End Sub
    20. End Class

    Jede Node ist entweder ein Menü (MenuNode) oder ein Programm (ProgramNode). Menüs können auch weitere Kind-Nodes haben (dadurch kommt die Baumstruktur zusammen).
    Das ist übrigens das "Composite"-Entwurfsmuster. Obwohl ich wenig davon halte, sich diese auswendig zu merken, hier der Wikipedia-Artikel: de.wikipedia.org/wiki/Kompositum_(Entwurfsmuster) Das UML-Diagramm könnte für das Verständnis helfen.

    Jede Node hat noch einen Verweis auf den ursprünglichen Datensatz, der die relevanten Daten angibt.
    Beachte dabei:
    Laut Deiner Tabelle in Post #4 gibt es zwei Menüs: MNU001 und MNU002. Aber es gibt nur einen Datensatz, der beschreibt, dass MNU002 MNU001 untergeordnet ist. Da die Objekte für sowohl MNU001, als auch MNU002 eine SourceRow-Eigenschaft haben, es aber nur einen Datensatz dafür gibt, muss einer von beiden Nothing sein. Der Code hier ist darauf ausgelegt, dass die MenuNodes, die keinen anderen MenuNodes untergeordnet sind (in diesem Fall also MNU001), auch SourceRow = Nothing haben. Ich kann gerade nicht gut in Worte fassen, warum das die bessere Variante ist, ohne einen ganzen Roman zu schreiben. Also versuch, es zu verstehen, und wenn Du dann noch Fragen hast, dann frag und ich erkläre es ;)

    Der Code, der aus einer Liste von CodeDataRows die Baumstruktur erstellt, sieht so aus:

    VB.NET-Quellcode

    1. Public Shared Sub Main(Args As String())
    2. 'Alle Datensätze auslesen.
    3. Dim AllNodeDataRows = GetAllNodeDataRows()
    4. 'Durchsuche die Datensätze nach allen vorkommenden ParentMenuName und erstelle für jeden eine MenuNode (praktischerweise in einem Dictionary abgelegt).
    5. Dim MenuNodesByName = AllNodeDataRows.Select(Function(i) i.ParentMenuName).Distinct.ToDictionary(Function(i) i, Function(i) New MenuNode With {.Name = i})
    6. 'Für alle Datensätze:
    7. For Each Row In AllNodeDataRows
    8. 'Beachte: Diese Prüfung auf die Art der Aktion ist suboptimal. Sollte sich das Format von ActionName irgendwann mal ändern, vergisst man garantiert, diesen Code auch zu ändern.
    9. 'Besser wäre, jedem Datensatz zusätzlich eine Spalte zu geben, die angibt, ob es sich um ein Programm oder ein Menü handelt.
    10. Select Case Row.ActionName.Substring(0, 3)
    11. Case "PRG"
    12. 'Handelt es sich um ein auszuführendes Programm, füge der durch ParentMenuName angegebenen Node ein ProgramNode-Objekt als Kind hinzu.
    13. MenuNodesByName(Row.ParentMenuName).ChildNodes.Add(New ProgramNode With {.SourceRow = Row})
    14. Case "MNU"
    15. 'Handelt es sich um ein Untermenü, füge der durch ParentMenuName angegebenen Node das entsprechende MenuNode-Objekt als Kind hinzu.
    16. Dim CurrentNode = MenuNodesByName(Row.ActionName)
    17. CurrentNode.SourceRow = Row
    18. MenuNodesByName(Row.ParentMenuName).ChildNodes.Add(CurrentNode)
    19. End Select
    20. Next
    21. 'Sortiere alle ChildNodes aller MenuNodes entsprechend der SortRank-Eigenschaft.
    22. Dim MenuNodes = MenuNodesByName.Select(Function(i) i.Value).ToList 'Zur Vereinfachung aus dem Dictionary rausgeholt. Nicht unbedingt nötig.
    23. For Each node In MenuNodes
    24. node.ChildNodes.Sort(Function(left, right) left.SourceRow.SortRank.CompareTo(right.SourceRow.SortRank))
    25. Next
    26. 'Alle Programme aller MenuNodes ausgeben.
    27. For Each Node In MenuNodes
    28. 'Alle MenuNodes, die keine SourceRow haben, sind Top-Level. Sind also nicht Kinder von anderen MenuNodes.
    29. 'Kommentiere das If-Statement zum Testen auch mal aus.
    30. If Node.SourceRow Is Nothing Then
    31. PrintWithIndentation(0, "Menu {0}", Node.Name)
    32. Dim Programs As New List(Of ProgramNode)
    33. Node.AccumulatePrograms(Programs)
    34. For Each Program In Programs
    35. PrintWithIndentation(1, "Program {0}", Program.SourceRow.ActionName)
    36. Next
    37. End If
    38. Next
    39. Console.WriteLine()
    40. Console.ReadLine()
    41. End Sub
    42. Private Shared Sub PrintWithIndentation(Level As Integer, Format As String, ParamArray Args As Object())
    43. Console.Write(New String(" "c, Level * 4))
    44. Console.WriteLine(Format, Args)
    45. End Sub

    Der Code sollte ausreichend dokumentiert sein, aber wenn Du Fragen hast, frag einfach.
    GetAllNodeDataRows gibt einfach alle Datensätze der Tabelle zurück. Ich habe den Code so geschrieben, dass die Datensätze in einer beliebigen Reihenfolge vorkommen können. Eventuell ließe sich ein bisschen was vereinfachen, wenn garantiert ist, dass Kind-Menüs und -Programme immer nach den übergeordneten Menüs vorkommen. Aber das ist fehleranfällig und der Code ist so ohnehin schon einfach genug.
    Zum Testen gebe ich einfach die Tabelle in Post #4 zurück:

    VB.NET-Quellcode

    1. Private Shared Function GetAllNodeDataRows() As List(Of NodeDataRow)
    2. Return New List(Of NodeDataRow) From _
    3. {
    4. New NodeDataRow With {.ParentMenuName = "MNU001", .ActionName = "PRG001", .SortRank = 1, .Description = "Programm 01"},
    5. New NodeDataRow With {.ParentMenuName = "MNU001", .ActionName = "PRG002", .SortRank = 2, .Description = "Programm 02"},
    6. New NodeDataRow With {.ParentMenuName = "MNU001", .ActionName = "MNU002", .SortRank = 3, .Description = "Menü 02"},
    7. New NodeDataRow With {.ParentMenuName = "MNU002", .ActionName = "PRG003", .SortRank = 1, .Description = "Programm 03"},
    8. New NodeDataRow With {.ParentMenuName = "MNU002", .ActionName = "PRG004", .SortRank = 2, .Description = "Programm 04"}
    9. }
    10. End Function

    Und die Ausgabe ist ganz einfach:

    Quellcode

    1. Menu MNU001
    2. Program PRG001
    3. Program PRG002
    4. Program PRG003
    5. Program PRG004

    Bzw. mit dem auskommentierten If-Statement:

    Quellcode

    1. Menu MNU001
    2. Program PRG001
    3. Program PRG002
    4. Program PRG003
    5. Program PRG004
    6. Menu MNU002
    7. Program PRG003
    8. Program PRG004

    Beachte, wie PRG003 und PRG004 in MNU001 und MNU002 vorkommen, PRG001 und PRG002 jedoch nur in MNU001. Denn im ersten Schleifendurchlauf wird die Frage gestellt: "Welche Programme befinden sich in MNU001?", welches MNU002 ja beinhaltet. Im zweiten Schleifendurchlauf wird aber nur nach MNU002 gefragt, welches die Programme von MNU001 eben nicht beinhaltet.

    Node.AccumulatePrograms macht dann genau das, was Du brauchst. Es findet alle ProgramNodes und fügt sie einer Liste hinzu. Rufst Du diese Methode an einer ProgramNode auf, ist das Ergebnis klar. Rufst Du diese Methode aber an einer MenuNode auf, wird sie erneut rekursiv für alle Nodes in MenuNode.ChildNodes aufgerufen. Und da drin befinden sich dann entweder ProgramNodes (die einfach zur Liste hinzugefügt werden) oder MenuNodes, für die wieder rekursiv weitergemacht wird.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    Hmm - der Begriff "StrukturAufbau" sagt mir nix.
    Deine Tabelle erinnert mich ans Aufbauen von Datei-Bäumen anhand flacher Datei-Listen.

    Aber bei deiner Tabelle blicke ich noch nicht hinters System.
    Ich bräuchte also noch ein bildle, was vergegenwärtigt, welche Ausgabe du erhalten willst.

    @Niko: ach so vlt.
    Aber ich Könnte mir auch vorstellen, dass die gesuchte Lösung so aussieht:

    Quellcode

    1. Menu MNU001
    2. Program PRG001
    3. Program PRG002
    4. Menu MNU002
    5. Program PRG003
    6. Program PRG004

    @ErfinderDesRades: Genau so soll die ausgabe aussehen
    @Niko Ortner: lässt sich das auch auf eine Prozedurale Sprache anwenden?
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    na, der erste Schritt wäre ein Linq-Einzeiler:

    VB.NET-Quellcode

    1. Dim Groups = from item in myTable Group by item.MenuName

    Das würde bereits in diese Ausgabe münden:

    Quellcode

    1. Menu MNU001
    2. Program PRG001
    3. Program PRG002
    4. Menu MNU002
    5. Menu MNU002
    6. Program PRG003
    7. Program PRG004
    Der 2.Schritt wäre komplizierter da müsste man gucken, welche Gruppe in welche andere Gruppe als UnterGruppe einzuhängen ist.
    Und zum Einhängen müsste man erstmal Datenklassen schaffen, die es erlauben, dass da was eingehängt wird.
    Was kann die Sprache? Bzw. um welche Sprache handelt es sich?
    Möglich ist es schon. Nur halt eventuell umständlicher. Aber solange man zumindest Structs verwenden kann, ist es kein Problem.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Niko Ortner schrieb:

    um welche Sprache handelt es sich?
    Wie in meinem zweiten Post geschrieben: ILE RPG.

    Niko Ortner schrieb:

    Was kann die Sprache?
    Verglichen mit Vb und C#: Nicht viel. RPG ist eine problemorientierte Programmiersprache für den kaufmännischen Bereich laut Wikipedia. Sie dient auf IBM Systemen zum abfragen von Datenbanken. Dabei kann der Zugriff entweder sequenziell oder wahlfrei erfolgen.
    Grundprinzip ist ein zyklisorientierter Programmablauf (RPG-Programme werden in einem Programmzyklus verarbeitet, dessen Schritte sich ständig wiederholen).
    Datenbanken werden typischerweise nach folgenden Muster abgefragt:
    Es wird auf einem Datensatz aufgesetzt und gelesen. Dieser Zugriff kann entweder (wie oben geschrieben) sequenziell erfolgen oder man kann mit sogenannten KeyLists einen Kombinations Key definieren, auf Basis dessen die Datenbank sortiert abgefragt/gelesen wird. Dann wird in mittels einer Do While Schleife (oder auch Do Until) Datensatz für Datensatz gelesen, bis kein Datensatz (der den Kriterien entspricht) mehr vorhanden ist.
    Falls sich wer auskennt: Am besten lässt sich RPG mit Cobol vergleichen.
    Dabei stehen zur Verfügung:
    - Arrays
    - Datenstrukturen (mehrere Felder werden zu einem Gesamtfeld zusammengebaut)
    - Grundlegende Kontrollstrukturen (If, Do While/Until, Switch Case, GoTo)

    Nicht zur Verfügung stehen:
    - Objektorientierung, da RPG eine Prozedurale Sprache ist
    - Rekursionen im Stile von VB (Aufruf mit Parametern)
    - Unterscheidung zwischen lokalen und globalen Variablen (jede Variable kann von überall im Programm verwendet werden)

    Lg Radinator
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Heißt das jetzt, dass du keine Möglichkeit hast, direkt auf SQL zurückzugreifen? Meiner Meinung nach wäre das ein typisches SQL-Problem und analog zu der Lösung von ErfinderDesRades zu lösen.
    Oder handelt es sich nicht um eine relationale Datenbank? Oder ist gar die Sprache dazu da, die Queries abzufragen und die wird dann optimiert?

    Viele Grüße
    ~blaze~
    Ich habe schon die möglichkeit das in SQL zu machen. Jedoch ENTWEDER in RPG ODER in SQL. Und da ich mit RPG eine Ausgabe erzeugen kann, die ich aus ausgedruckt irgendwo verwenden kann oder sie zumindest als PDF weiter verarbeiten kann, wäre mir diese Art doch lieber.

    @~blaze~: Was meinst du mit relationale Datenbank?
    Ich habe nur eine Tabelle, in welcher ich die Daten, wie in meinem ersten Post, gespeichert habe.

    ~blaze~ schrieb:

    Oder ist gar die Sprache dazu da, die Queries abzufragen
    Nein. Die Sprache ist (aufgrund des Namens: RPG = Report Programm Generator - Lister Erzeugungs Sprache) grundsätzlich nur dafür gedacht (kaufmännische) Liste zu erstellen. Also meinetwegen auf Basis eines Artikel- und Lieferanten stamms herauszufinden, welche Artikel von welchem Lieferanten geliefert werden. Dabei wird - je nach Bedarf - die eine Tabelle als "Primär Datei" genommen, sequenziell durchgelesen und mit dem Fremdschlüssel auf die andere Tabelle gegangen und die benötigten Daten in den aktuellen Kontext geholt. Dann bei Bedarf entweder in einer anderen Tabelle ausgegeben oder an den Drucker geschickt, der die Daten dann ausdruckt.

    Hier ein Codebeispiel:

    Brainfuck-Quellcode

    1. C* ---------------------------------------------------------------------
    2. C* Test Prozedur
    3. C* ---------------------------------------------------------------------
    4. C tstprc begsr Prozedur Definition
    5. C
    6. C *loval setll artdb Aufsetzen auf DB
    7. C read artdb 40 Sequenzielles Lesen
    8. C *in40 doweq *off Do While Schleife
    9. C
    10. C z-add adlinr ldlinr Mit Artikelnummer
    11. C ldlinr chain lifdb 41 auf Lieferantendatei
    12. C *in40 ifeq *off Wenn gefunden
    13. C exsr prtart Ausgabe ausführen
    14. C endif
    15. C
    16. C read artdb 40 Nächsten Datensatz
    17. C enddo
    18. C
    19. C endsr


    Oder Pseudocode:

    Quellcode

    1. BEGINN:
    2. Aufsetzen auf ersten Datensatz
    3. Lesen des ersten Datensatzes
    4. Solange Datensatz gefunden
    5. Mit Fremdschlüssel in zweiter Datenbank suchen
    6. Wenn Datensatz gefunden
    7. Ausgabe
    8. Ende Wenn
    9. Nächsten Datensatz lesen
    10. Ende Solange
    11. ENDE


    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Radinator“ ()

    Laut Schnellst-Überfliegen des Wikipedia-Artikels zu IBM RPG gibt es die Möglichkeit, SQL darin zu verwenden. Also: SQL-Query auf der Datenbank ausführen und das dann drucken... Die Datenbank kann das sowieso weitaus effizienter lösen, als ein Algorithmus, den du ansetzt, die sind ja darauf optimiert.

    Relationale Datenbank bedeutet, dass es sich um eine Datenbank handelt, die auf dem relationalen Datenmodell basiert, im Gegensatz zu z.B. graphorientierten Datenbanken, die auf Graphen basieren, anstatt auf Relationen (sind halt gewisse Unterschiede).

    Viele Grüße
    ~blaze~

    ~blaze~ schrieb:

    im Gegensatz zu z.B. graphorientierten Datenbanken, die auf Graphen basieren, anstatt auf Relationen
    Sehr hilfreich ;D
    Ne Spaß beiseite. Leider weiß ich mit dem Vergleich zwischen Graphen und Relationen nichts anzufangen.

    Zu dem, dass man SQL einbinden kann: Ja kann man. Auch auf den Ansatz von @EDR bin ich auch schon gekommen. Das funzt auch wunderbar, solange ich nur einen einfache verschachtlung der Einträge habe (Nur eine Ebene). Doch wie soll das dann mit weiteren Ebenen funktionieren?

    Lg Radinator
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Radinator schrieb:

    Brainfuck-Quellcode

    Wie passend :D Ich dachte erst, das wäre Assembly.

    Radinator schrieb:

    Datenstrukturen (mehrere Felder werden zu einem Gesamtfeld zusammengebaut)

    Das sollte ausreichen.
    Verschiebe die AccumulatePrograms-Methode aus den Klassen raus und führe die Klassen zusammen:

    VB.NET-Quellcode

    1. Public Enum NodeType
    2. MenuNode = 1
    3. ProgramNode = 2
    4. End Enum
    5. Public Class Node
    6. 'Zur Hilfe
    7. Public Property NodeType As NodeType
    8. 'Gemeinsam
    9. Public Property SourceRow As NodeDataRow
    10. 'MenuNode
    11. Public Property Name As String
    12. Public Property ChildNodes As New List(Of Node)
    13. 'ProgramNode
    14. '(Nichts)
    15. End Class
    16. Public Shared Sub AccumulatePrograms(Node As Node, Programs As List(Of ProgramNode))
    17. Select Case Node.NodeType
    18. Case NodeType.MenuNode
    19. For Each i In Node.ChildNodes
    20. AccumulatePrograms(i, Programs)
    21. Next
    22. Case NodeType.ProgramNode
    23. Programs.Add(Node)
    24. End Select
    25. End Sub

    So könnte das funktionieren. Ist nicht so schön, geht aber auch.
    Den restlichen Code musst Du natürlich auch ein bisschen abändern. Also z.B.:

    VB.NET-Quellcode

    1. MenuNodesByName(Row.ParentMenuName).ChildNodes.Add(New ProgramNode With {.SourceRow = Row})
    2. 'Ändern in
    3. MenuNodesByName(Row.ParentMenuName).ChildNodes.Add(New Node With {.NodeType = NodeType.ProgramNode, .SourceRow = Row})
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Danke @Niko Ortner für deinen Post! :D

    Nur leider kann ich in RPG keine Klassen verwenden!

    Niko Ortner schrieb:

    Verschiebe die AccumulatePrograms-Methode aus den Klassen raus und führe die Klassen zusammen:
    Ändert das was?

    Sry fürs dumme fragen, aber ich steh da irgendwie komplett an

    Lg Radinator
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Du hast ja "Datenstrukturen (mehrere Felder werden zu einem Gesamtfeld zusammengebaut)" geschrieben.
    Ob das nun Klassen, Strukturen oder assoziative Arrays sind, ist eigentlich nicht so tragisch.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Verwende halt rekursive Queries oder was auch immer du benötigst. SQL ist so mächtig, dass du da wohl auf jeden Fall fündig wirst. Und falls nicht, dann strukturiere das Programm so, dass du mehrere Queries herausschickst, die die Sachen erledigen, die du benötigst. Beachte aber, dass sich die Datenbank in diesem Fall zwischenzeitlich ändern kann.

    Viele Grüße
    ~blaze~