CSV Reader und Code-Optimierung

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Ryke.

    CSV Reader und Code-Optimierung

    Guten Abend zusammen, ich bin aus der Versenkung aufgetaucht!

    Ich bin seit einigen Wochen an einem Programmier-Projekt zugange, welches ich als Game Master bei einem Pen&Paper Spiel einsetzen möchte. Anfänglich war ich eher sporadisch am programmieren, da ich keinen richtigen Anfang gefunden habe, ich musste sehr viel Googeln und habe die meiste Hilfe gezielt in diesen Foren gesucht (Danke an dieser Stelle an alle von euch!). Nun bin ich soweit, dass ich ein Programm habe, welches meine CSV-Dateien einliest, sie in einer DataGridView auf einer Windows-Form mit TabControl ausgibt und ich habe auch die Funktion einer rudimentären Filterung der Quelldaten implementiert.

    Das ganze tut was es soll und ich arbeite weiterhin daran, ich möchte aber natürlich auch gerne weiterhin etwas Neues lernen und bitte euch, einen Blick auf meinen Code zu werfen. Ich bin mir sicher, dass es bessere Wege gibt, als die, die ich gegangen bin. Was mich am meisten stört ist die viele Redundanz.

    Das Spiel wird im Pokemon-Universum (nur erste Generation) stattfinden und ich habe mir einige Habitate ausgedacht. Jeder Tab im TabControl entspricht einem Habitat und pro Tab habe ich ein DataGridView. Im Code spreche ich nun jedes DataGridView separat an und fülle die Spalten und Zeilen.Das lässt sich doch bestimmt dynamisch gestalten. Ich habe das auch mal einen Lösungsansatz gehabt, allerdings sind mir dabei 1-2 Funktionen "kaputt" gegangen. Zum Beispiel möchte ich Tag- und Nachtaktiv selektieren können, sodass mir entsprechende Pokemon aufgelistet werden. Außerdem sollen alle Pokemon, welche ich in diesem Habitat nicht antreffen werde, also 0% Chance, gar nicht angezeigt werden. Ich habe also 2 Datenquellen:

    CSV 1: Liste Aller Pokemon(Nummer, Name, Typ1, Typ2, Nachtaktiv J/N) : PkmnList.csv
    CSV 2: Chance in diesem Habitat : [HabitatName].csv

    Ich habe die gesamte Projektmappe diesem Post angehängt, damit ihr (hoffentlich) alles habt, ihr braucht.
    In dem Ordner CSVReader\CSV\Habitate sind alle CSV-Dateien, die ich eingebunden habe.

    Außerdem habe ich die Projektmappe auf einem USB-Stick liegen, der Pfad der Dateien ist also relativ starr hinterlegt. Der Laufwerksbuchstabe kann im Laufenden Betrieb geändert werden (Tab Config), dann nochmal auf "einlesen" klicken und es sollte laufen.

    Ich wünsche mir weniger Redundanz im Code und idealerweise kann ich die einzelnen Chancen im Programm verändern (ja, die DGVs sind auf Read-Only gesetzt, das müsste man natürlich ändern) und in der jeweiligen CSV speichern. Das hatte ich testweise auch schon aktiv, bloß werden mir dann nicht alle Einträge gespeichert, da ich ja viele rausfiltere (weil 0% Chance).

    Vielen Dank im Voraus für die, gewohnt kompetente und freundliche, Hilfe und Ich hoffe ich habe hier das korrekte Forum erwischt, falls nicht, bitte ich um Verzeihung!
    Dateien
    • CSVReader.zip

      (652,08 kB, 68 mal heruntergeladen, zuletzt: )
    Eine Pizza auf einer Pizza sind 2 Pizzen

    Eine Lasagne auf einer Lasagne ergibt 1 große Lasagne
    @Ryke Ohne jetzt Deinen Code analysiert zu haben:
    Warum packst Du Deine Daten in eine CSV-Datei?
    Pack alle Deine Daten in eine XML-serialisierbare Klasse und leg die als XML auf der Platte ab.
    Da musst Du Dich um nichts weiter kümmern und feddich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Vielen Dank für die schnelle Antwort!

    Weil ich jetzt schon nicht weiß, was du meinst ?(
    Ich habe CSV gewählt, weil ich das kenne und als ich dieses Projekt begonnen habe, hatte ich keine Ahnung wie irgendwas bezüglich CSV und VB-Net funktioniert.

    Wenn XML besser ist, nehme ich das sonst auch gerne. Soweit ich weiß, lässt sich XML ja ähnlich bearbeiten. Bloß was du mit dieser Klasse meinst... Keine Ahnung wie ich das auch nur anfangen sollte. Ich wollte jetzt allerdings auch nicht unbedingt ganz von vorne beginnen.
    Eine Pizza auf einer Pizza sind 2 Pizzen

    Eine Lasagne auf einer Lasagne ergibt 1 große Lasagne
    Die Redundanzen kannst Du durch eine geeignete Parameterliste beseitigen. Wenn Du der Prozedur XYZ_ZeilenInhalte das Ziel-DGV, einen String wie Form1.Berg und das Ziel-Array (z.B. Zeilen_Berg_Chancen) übergibst, kannst Du aus vielen Prozeduren eine machen. Probier es, danach machen wir auf Wunsch den Code und auch die Programmstruktor noch besser.
    Mach mal bitte den VB6-Namespace raus.
    An der Benennung solltest Du noch etwas feilen. Ein Prozedurname wie Berg_ZeilenInhalte ist wenig informativ. Solch ein Name sollte m.E. immer sagen, was die Prozedur macht. Denn jede Prozedur sollte was machen. Dementsprechend sollte sie ein zutreffendes Verb enthalten.
    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.
    ich hab mal bischen was angefangen umzuarbeiten.
    Ein Hauptproblem ist, dass du Methoden keine Argumente übergibst. Stattdessen hast du Klassenvariablen.
    Konkret:
    Für jedes Habitat hast du eine eigene Klassenvariable.
    Daraus folgt, dass du für jedes Habitat auch eine eigene EinleseMethode hast. Weil WüsteZeilenEinlesen arbeitet mit der Wüste-KlassenVariable, und BergZeilenEinlesen mit der Berg-Klassenvariablen usw.
    So entsteht eine Unmenge Code der alles das gleiche macht, jeweils mit anderen Variablen.
    Ich hab mir die WüsteEinleseMethode geschnappt, und übergebe ihr die veränderlichen Variablen als Parameter (Variable heisst übrigens: Veränderlich).
    Und dann benenne ich sinnvoll um - nämlich ich abstrahiere: Aus konkret:"Wueste", "Berg", "Hoehle" wird verallgemeinert: "habitat" - und das kann alle diese vorgenannten sein. UndSoweiter.
    Aus so:

    VB.NET-Quellcode

    1. Sub Wueste_ZeilenInhalte()
    2. Chance = Split(Wueste, vbCrLf)
    3. Zeile = 0
    4. For i = 0 To Chance.Length - 1
    5. Chance(i) = Chance(i).Remove(0, 4) 'Entfernt die ersten 4 Zeichen --> 001;0 wird zu 0
    6. Zeilen_Wueste_Chancen(i) = CInt(Chance(i)) 'Wandelt den String "0" in die Zahl 0 um und weist sie zu
    7. Next
    8. For i = 0 To Zeilen_Wueste_Chancen.Length - 1
    9. If TagNacht = "Tag" And Nachtaktiv(i) = "Nein" And Zeilen_Wueste_Chancen(i) <> 0 Then
    10. DataGridView_Wueste.Rows.Add(Split(Zeilen_Pkmn_List(i), ";"))
    11. DataGridView_Wueste.Item(Spalte_Chancen, Zeile).Value = Zeilen_Wueste_Chancen(i)
    12. Zeile += 1
    13. End If
    14. If TagNacht = "Nacht" And Nachtaktiv(i) = "Ja" And Zeilen_Wueste_Chancen(i) <> 0 Then
    15. DataGridView_Wueste.Rows.Add(Split(Zeilen_Pkmn_List(i), ";"))
    16. DataGridView_Wueste.Item(Spalte_Chancen, Zeile).Value = Zeilen_Wueste_Chancen(i)
    17. Zeile += 1
    18. End If
    19. Next
    20. End Sub

    wird so:

    VB.NET-Quellcode

    1. Private Sub Habitat_ZeilenInhalte(fileName As String, habitatChancen As Integer(), dgv As DataGridView)
    2. Dim habitat = File.ReadAllText(HabitatePfad & fileName)
    3. Dim Chance = Split(habitat, vbCrLf)
    4. Dim Zeile = 0
    5. For i = 0 To Chance.Length - 1
    6. Chance(i) = Chance(i).Remove(0, 4) 'Entfernt die ersten 4 Zeichen --> 001;0 wird zu 0
    7. habitatChancen(i) = CInt(Chance(i)) 'Wandelt den String "0" in die Zahl 0 um und weist sie zu
    8. Next
    9. For i = 0 To habitatChancen.Length - 1
    10. If TagNacht = "Tag" And Nachtaktiv(i) = "Nein" And habitatChancen(i) <> 0 Then
    11. dgv.Rows.Add(Split(Zeilen_Pkmn_List(i), ";"))
    12. dgv.Item(Spalte_Chancen, Zeile).Value = habitatChancen(i)
    13. Zeile += 1
    14. End If
    15. If TagNacht = "Nacht" And Nachtaktiv(i) = "Ja" And habitatChancen(i) <> 0 Then
    16. dgv.Rows.Add(Split(Zeilen_Pkmn_List(i), ";"))
    17. dgv.Item(Spalte_Chancen, Zeile).Value = habitatChancen(i)
    18. Zeile += 1
    19. End If
    20. Next
    21. End Sub
    Ich bin dabei noch einen Schritt weiter gegangen - ich bekomme nicht das habitat übergeben, sondern nur noch den Dateinamen - das habitat kann ich dann selbst einlesen.
    Aufrufen kann ich so:

    VB.NET-Quellcode

    1. Habitat_ZeilenInhalte("Berg.csv", Zeilen_Berg_Chancen, DataGridView_Berg)
    2. Habitat_ZeilenInhalte("Donnertundra.csv", Zeilen_Donnertundra_Chancen, DataGridView_Donnertundra)
    3. Habitat_ZeilenInhalte("Hoehle.csv", Zeilen_Hoehle_Chancen, DataGridView_Hoehle)
    4. Habitat_ZeilenInhalte("Huegel.csv", Zeilen_Huegel_Chancen, DataGridView_Huegel)
    5. Habitat_ZeilenInhalte("Kueste.csv", Zeilen_Kueste_Chancen, DataGridView_Kueste)
    6. Habitat_ZeilenInhalte("Polar.csv", Zeilen_Polar_Chancen, DataGridView_Polar)
    7. Habitat_ZeilenInhalte("Ruinen.csv", Zeilen_Ruinen_Chancen, DataGridView_Ruinen)
    8. Habitat_ZeilenInhalte("Sumpf.csv", Zeilen_Sumpf_Chancen, DataGridView_Sumpf)
    9. Habitat_ZeilenInhalte("Vulkan.csv", Zeilen_Vulkan_Chancen, DataGridView_Vulkan)
    10. Habitat_ZeilenInhalte("Wald.csv", Zeilen_Wald_Chancen, DataGridView_Wald)
    11. Habitat_ZeilenInhalte("Wasser.csv", Zeilen_Wasser_Chancen, DataGridView_Wasser)
    12. Habitat_ZeilenInhalte("Wiese.csv", Zeilen_Wiese_Chancen, DataGridView_Wiese)
    13. Habitat_ZeilenInhalte("Wueste.csv", Zeilen_Wueste_Chancen, DataGridView_Wueste)
    Und nun können folgende Variablen und Methoden verschwinden:

    VB.NET-Quellcode

    1. Berg, Donnertundra, Hoehle, Huegel, Kueste, Polar, Ruinen, Sumpf, Vulkan, Wald, Wasser, Wiese, Wueste
    2. Sub Berg_ZeilenInhalte()
    3. Sub Donnertundra_ZeilenInhalte()
    4. Sub Hoehle_ZeilenInhalte()
    5. Sub Huegel_ZeilenInhalte()
    6. Sub Kueste_ZeilenInhalte()
    7. Sub Polar_ZeilenInhalte()
    8. Sub Ruinen_ZeilenInhalte()
    9. Sub Sumpf_ZeilenInhalte()
    10. Sub Vulkan_ZeilenInhalte()
    11. Sub Wald_ZeilenInhalte()
    12. Sub Wasser_ZeilenInhalte()
    13. Sub Wiese_ZeilenInhalte()
    14. Sub Wueste_ZeilenInhalte()
    Das macht schon ziemlich was aus.



    Nun bist du dran: Lass diese Klassenvariablen verschwinden:

    VB.NET-Quellcode

    1. Public Zeilen_Berg_Chancen(150) As Integer
    2. Public Zeilen_Donnertundra_Chancen(150) As Integer
    3. Public Zeilen_Hoehle_Chancen(150) As Integer
    4. Public Zeilen_Huegel_Chancen(150) As Integer
    5. Public Zeilen_Kueste_Chancen(150) As Integer
    6. Public Zeilen_Polar_Chancen(150) As Integer
    7. Public Zeilen_Ruinen_Chancen(150) As Integer
    8. Public Zeilen_Sumpf_Chancen(150) As Integer
    9. Public Zeilen_Vulkan_Chancen(150) As Integer
    10. Public Zeilen_Wald_Chancen(150) As Integer
    11. Public Zeilen_Wasser_Chancen(150) As Integer
    12. Public Zeilen_Wiese_Chancen(150) As Integer
    13. Public Zeilen_Wueste_Chancen(150) As Integer

    Schreibe für diesen RedundanzKram ebenfalls eine kleine Methode mit Parametern:

    VB.NET-Quellcode

    1. Case 0 'Berg
    2. For i = 0 To DataGridView_Berg.Rows.Count - 1
    3. iTemp = CInt(DataGridView_Berg.Item(Spalte_Chancen, i).Value)
    4. If iTemp = chance Then
    5. DataGridView_Berg.Item(Spalte_Chancen, i).Style.BackColor = Color.LightGreen
    6. Else
    7. DataGridView_Berg.Item(Spalte_Chancen, i).Style.BackColor = Color.White
    8. End If
    9. Next
    10. Case 1 'Donnertundra
    11. For i = 0 To DataGridView_Donnertundra.Rows.Count - 1
    12. iTemp = CInt(DataGridView_Donnertundra.Item(Spalte_Chancen, i).Value)
    13. If iTemp = chance Then
    14. DataGridView_Donnertundra.Item(Spalte_Chancen, i).Style.BackColor = Color.LightGreen
    15. Else
    16. DataGridView_Donnertundra.Item(Spalte_Chancen, i).Style.BackColor = Color.White
    17. End If
    18. Next
    19. Case 2 'Hoehle
    20. For i = 0 To DataGridView_Hoehle.Rows.Count - 1
    21. iTemp = CInt(DataGridView_Hoehle.Item(Spalte_Chancen, i).Value)
    22. If iTemp = chance Then
    23. DataGridView_Hoehle.Item(Spalte_Chancen, i).Style.BackColor = Color.LightGreen
    24. Else
    25. DataGridView_Hoehle.Item(Spalte_Chancen, i).Style.BackColor = Color.White
    26. End If
    27. Next
    28. '...
    Es soll sowas bei rauskommen:

    VB.NET-Quellcode

    1. Select Case Tab
    2. Case 0 : ColoriereDGV(DataGridView_Berg)
    3. Case 1 : ColoriereDGV(DataGridView_Donnertundra)
    4. Case 2 : ColoriereDGV(DataGridView_Hoehle)
    5. Case 3 : ColoriereDGV(DataGridView_Huegel)
    6. '...
    Dateien
    • CSVReader00.zip

      (584,9 kB, 62 mal heruntergeladen, zuletzt: )

    Ryke schrieb:

    Weil ich jetzt schon nicht weiß, was du meinst
    Ich hänge Dir mal ein Beispielprojekt an.
    Mach eine Form mit 3 Button und einer ListBox:
    Form

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private XmlFile As String = "c:\temp\data.xml" ' Pfad zum Speichern / Lesen
    3. Private Data As MyData
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. ' Daten-Instanz erstellen und befüllen
    6. Me.Data = New MyData With {
    7. .Name = "Test Status",
    8. .Address = "0000",
    9. .Type = 9999,
    10. .Timestamp = DateTime.Now,
    11. .Flags = 0,
    12. .User = "Tester",
    13. .SingleValues = New List(Of Integer) From {1, 2, 3, 4, 5}
    14. }
    15. End Sub
    16. ''' <summary>
    17. ''' Daten auf Festplatte schreiben
    18. ''' </summary>
    19. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    20. Me.Data.WriteData(Me.XmlFile)
    21. End Sub
    22. ''' <summary>
    23. ''' Daten von Festplatte laden
    24. ''' </summary>
    25. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    26. Me.Data = MyData.LoadData(Me.XmlFile)
    27. End Sub
    28. ''' <summary>
    29. ''' aktuelle Daten darstellen
    30. ''' </summary>
    31. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    32. Me.ListBox1.Items.Clear()
    33. ' hier: nur das Integer-Array
    34. For Each value In Me.Data.SingleValues
    35. Me.ListBox1.Items.Add(value)
    36. Next
    37. End Sub
    38. End Class
    Datenklasse
    Imports System.IO
    Imports System.Text
    Imports System.Xml.Serialization

    ''' <summary>
    ''' Datenklasse
    ''' </summary>
    ''' <remarks>mit XML-Serialisierung</remarks>
    Public Class MyData
    ' alle vorkommenden Daten
    Public Property Name() As String
    Public Property Address() As String
    Public Property Type() As Integer
    Public Property Timestamp() As DateTime
    Public Property Flags() As Integer
    Public Property User() As String
    Public Property SingleValues() As List(Of Integer)

    Public Sub New()
    ' Hier die Daten mit Defaultwerten befüllen oder nicht
    Me.Name = "Hase"
    Me.SingleValues = New List(Of Integer)
    End Sub

    ''' <summary>
    ''' Daten aus einer Datei lesen
    ''' </summary>
    ''' <param name="file">Dateiname</param>
    ''' <returns>die geladene Instanz</returns>
    Public Shared Function LoadData(file As String) As MyData
    Dim data As New MyData()
    Try
    ' Deserialize XML file to a new object.
    Using sr As New StreamReader(file, Encoding.Default)
    Dim x As New XmlSerializer(data.GetType())
    data = DirectCast(x.Deserialize(sr), MyData)
    End Using
    Return data
    Catch
    ' nix tun, die Daten-Instanz ist nicht valid,
    ' es wird die Instanz übergeben, die bei New() erzeugt wird
    End Try
    Return data
    End Function

    ''' <summary>
    ''' Daten in eine Datei schreiben
    ''' </summary>
    ''' <param name="file">Dateiname</param>
    Public Sub WriteData(file As String)
    ' Serialize object to a XML file.
    Using sw As New StreamWriter(file, False, Encoding.Default)
    Dim x As New XmlSerializer(Me.GetType())
    x.Serialize(sw, Me)
    End Using
    End Sub
    End Class

    Erstell eine Datenklasse nach Deinen Bedürfnissen, füge ihr die Lese- und Scheibe-Prozedur und feddich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ErfinderDesRades : Vielen herzlichen Dank! Das geht genau in die Richtung, in die ich wollte! Sobald ich Zeit habe, setze ich mich da nochmal ran und versuche deine Vorschläge umzusetzen! ^^

    @RodFromGermany : Auch dir vielen Dank! Ich werde mir das ebenfalls ansehen und mal schauen, wie viel ich davon umgesetzt bekomme!

    @VaporiZed : Danke für den Hinweis, ich werde ihn beherzigen ;) Was hat es mit dem VB6 Namespace auf sich?

    Ich melde mich wieder, wenn ich soweit bin :thumbsup:
    Eine Pizza auf einer Pizza sind 2 Pizzen

    Eine Lasagne auf einer Lasagne ergibt 1 große Lasagne
    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.
    Guten Abend zusammen,

    ich habe nun mal Zeit gefunden mich an all eure Vorschläge heranzusetzen.

    @ErfinderDesRades Bei dem Versuch die Klassenvariablen verschwinden zu lassen, ist mir aufgefallen, dass du sie ja ohnehin ja obsolet gemacht hast. Also wollte ich deine Methode um einen Parameter erleichtern:

    VB.NET-Quellcode

    1. ​Private Sub Habitat_ZeilenInhalte(fileName As String, habitatChancen As Integer(), dgv As DataGridView)


    wird zu

    VB.NET-Quellcode

    1. ​Private Sub Habitat_ZeilenInhalte(fileName As String, dgv As DataGridView)


    Und innerhalb der Methode habe ich eine Variable hinzugefügt:

    VB.NET-Quellcode

    1. Dim habitat = File.ReadAllText(HabitatePfad & fileName)
    2. Dim Chance = Split(habitat, vbCrLf)
    3. Dim Zeile = 0
    4. Dim habitatChancen As Integer() = {}


    Ich glaube das ist der richtige Weg.
    Nun bin ich aber, wieder, über eine bestimmte Frage gestolpert:

    Es gibt ja mehrere Wege ein Array zu deklarieren, diese 3 sind mir aktuell geläufig und ich habe mich dazu auch schon ein wenig belesen, allerdings bin ich aus dem Wust an Antworten nicht wirklich schlau geworden. Dass mein Programm überhaupt soweit kam und funktioniert ist sicherlich auch viel Glück gewesen. Aber ich möchte gerne wissen was ich tue. Kann mir einer von euch erklären, was diese 3 Deklarationsarten unterscheidet?

    VB.NET-Quellcode

    1. Dim habitatChancen As Integer() = {}
    2. Dim habitatChancen As Integer(150) = {}
    3. Dim habitatChancen() As Integer = {}


    und, @ErfinderDesRades bin ich auf dem richtigen Wege was deinen Vorschlag angeht?

    @RodFromGermany Das mit der XML Klasse schaue ich mir an, wenn ich das hier auf der Kette habe. Ich möchte nicht hin und her springen und mich selbst (noch mehr) verwirren.

    Ich mache gerne mehr Schritte als nötig, wenn ich dafür den Überblick behalte und alles besser verstehe. Wenn der Lerneffekt dann eingesetzt hat, lasse ich die überflüssigen Schritte auch weg :)
    Eine Pizza auf einer Pizza sind 2 Pizzen

    Eine Lasagne auf einer Lasagne ergibt 1 große Lasagne

    Ryke schrieb:

    und, @ErfinderDesRades bin ich auf dem richtigen Wege was deinen Vorschlag angeht?
    Jo - für habitatChancen ist ebenfalls eine lokale Variable das richtige.
    Zu die verschiedenen Weisen, ein Array zu deklarieren: Ja, ist ziemlich bescheuert gelöst in vb.net.
    Dazu gibts auch hier einen Abschnitt: Grundlagen: Fachbegriffe
    Guten Abend zusammen,

    ich habe mich zwischendurch immer mal wieder an die Optimierungen herangesetzt, ich stolpere aber immer wieder bei den Arrays...
    Der Link, den ErfinderDesRades gepostet hat, den habe ich bereits beim Googeln entdeckt und da wurde ich daraus schon nicht schlau.

    Ich weiß jetzt zwar, dass man ein Array auf diverse Arten deklarieren kann, aber ich weiß nicht welche nun die Richtige für mich ist.

    Mein Programm füllt aktuell die Tabellen nicht mehr mit den Zeilen und ich habe ehrlich gesagt keine Ahnung, warum es das nicht mehr tut...
    Wie kann ich euch nun am besten Helfen mir zu helfen?
    Eine Pizza auf einer Pizza sind 2 Pizzen

    Eine Lasagne auf einer Lasagne ergibt 1 große Lasagne