Mit einer for-Schleife mehrere Werte ermitteln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
buzi
User
Beiträge: 2
Registriert: Samstag 30. Juli 2016, 09:32

Hallo

ich bin dabei, hobbymäßig etwas Programmieren zu lernen, indem ich mit Python versuche einen str8tssolver zu realisieren. (str8ts ist ein Zahlenrätsel ähnlich Sudoku aber mit komplexeren Regeln.) Ich komme auch ganz gut voran, scheitere jetzt aber an einem Problem, das sich simpel anhört, sicher auch einfach zu realisieren ist, ich aber auch nach vielen Stunden Nachdenkens und Probierens nicht weiter weiß. Das liegt wohl daran, dass ich nicht wirklich verstanden habe, wie das Iterieren genau abläuft.

Ich versuche, nur das zu beschreiben, was für die Fragestellung von Bedeutung ist:

Das Spiel hat 36 Felder, numeriert von 0 bis 35. Jedem Feld sind diverse Variable zugeordnet, die in dem Array "fe" definiert sind. Eine Variable ist die Zahl, die auf dem Feld steht (die Zahlen 1 bis 6 sind möglich) eine andere Variable die Straße fe[3], zu der das Feld gehört.

Das Spiel hat maximal 18 Straßen, numeriert von 0 bis 17. Jeder Straße sind diverse Variable zugeordnet, die in dem Array "stze" definiert sind. Eine Variable ist die Liste der Feldnummern stze[4][n], die zu der Straße gehören (2 bis 6 Feldnummern sind möglich).

Im Array "fe" sind durch die vorhandenen Funktionen bereits die Straßen eingetragen. Jetzt sollen im Array "stze" die Feldnummern stze[4][n] dazu eingetragen werden, und daran scheitere ich. Folgender simpler Ansatz kommt von denen, die mir eingefallen sind, noch am nächsten:

Code: Alles auswählen

for i in range(36):
	for m in range(18):
		for n in range(6):
			if fe[i][3] == stze[m][0]:
				stze[m][4][n] = fe[i][0]
Das Ergebnis ist, dass in der Liste der Feldnummern-Variablen sechsmal die höchste Feldnummer der Straße eingetragen wird und nicht z.B. für eine Straße, bestehend aus den Feldern 3 und 4 wie gehofft nur stze[4][0] = 3 und stze[4][1] = 4. Das Iterieren mit m führt offensichtlich dazu, dass der vorher gefundene Wert vom nächsten gefundenen Wert überschrieben wird. Vielleicht käme ich schon weiter, wenn ich wüsste wie jeder beim Iterieren gefundene Wert, der die genannte Bedingung erfüllt, getrennt abgespeichert werden kann.

Ich weiß, dass der beschriebene Lösungsversuch den Eindruck erweckt, als ob ich es mir sehr leicht gemacht habe. Aber ich habe wirklich diverse Wege versucht, ohne Erfolg. Den "Offenen Brief an Pythonneulinge" habe ich gelesen, aber auch die dort empfohle/geforderte Suche nach for-Schleife, Iteration, Bedingte Anweisung usw. hat mir auch nicht weiter geholfen.

Ist jemand bereit, mir zu helfen, mit Formulierungen, die ein Anfänger verstehen kann?
Wie ihr seht, komme ich mit der MoinWikiSyntax nicht klar, ich bitte das zu entschuldigen.
Zuletzt geändert von Anonymous am Samstag 30. Juli 2016, 10:39, insgesamt 1-mal geändert.
Grund: Formatierung korrigiert.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was mir da sofort auffaellt: ich halte deine Datenstruktur fuer ungeeignet. Nachdem ich gerade mal selbst ein Stra8s geloest habe, ist klar, dass es uA aenhliche raeumliche Randbedingungen wie SUDOKU hat - sprich, die Zahlen in den 4 Richtungen relativ zum aktuellen Feld spielen eine Rolle. Damit ist in meinen Augen ein zweidimensionales Array (also wohl 6x6 in deinem Fall) notwendig.

Danach sind die verschiedenen Attribute die du definierst durch eine Listenstruktur schlecht geloest. Nimm stattdessen eine namedtuple, um einen klar benamten Zugriff auf die verschiedenen Attribute zu haben.

Ein aehnliches Problem: Deine Variablennamen sind unguenstig gewaehlt. Ist "stze" ernsthaft eine Verbesserung gegenueber "strassen"?

Und ich verstehe auch nicht, wie genau diese "stze"-Struktur aufgebaut ist, da wird wieder wild rumindiziert. Auch unlesbar.

Wenn ich das loesen sollte, wuerde ich erst einmal damit anfangen, die zweidimensionale Struktur aufzubauen, die all die Informationen enthaelt, die der Spieler auch bekommt: Ist ein Feld schwarz oder weiss, und welche Zahl steht darauf. Das war's.

Wenn du das aufgebaut hast, koennen wir versuchen, weiter zu kommen.
BlackJack

@buzi: Der Code sieht nicht nach Python aus, sondern das Du versuchst eine andere Sprache in Python-Syntax zu übersetzen. Das mache in an den Schleifen über Index-Laufvariablen und den Listen mit Dummywerten fest, die in diesen Schleifen dann nacheinander durch die tatsächlichen Werte ersetzt werden. Und daran das Du Listen als Arrays bezeichnest.

Indexoperationen sind in Python wesentlich seltener als zum Beispiel in C oder Pascal. Man kann *direkt* über die Elemente von Sequenztypen, wie Listen iterieren. Die Schleifen würde in Python also eher so aussehen:

Code: Alles auswählen

    for field in fe:
        for street in stze:
            for n in xrange(6):
                if field[3] == street[0]:
                    street[4][n] = field[0]
Die Datenstruktur mit den verschachtelten Listen, den magischen Indexwerten deren Bedeutung man kennen muss, und die schlechten Namen `fe` und `stze` sind auch nicht wirklich schön. Wenn man sich den Code weiter oben anschaut, würde für `fe` wahrscheinlich `fields` und für `stze` der Name `streets` Sinn machen.

Und dann kann man mit Objekten und Attributen die schlecht lesbaren magischen Indexwerte beseitigen.

Code: Alles auswählen

    for field in fields:
        for street in streets:
            for n in xrange(6):
                if field.street_id == street.id:
                    street.field_ids[n] = field.id
An dem Code sieht man nun viel besser, dass der entweder keinen Sinn macht, oder aber zu umständlich geschrieben ist. Denn in der innersten Schleife ändern sich weder `field` noch `street`, also ändert sich die Bedingung beim ``if`` nie und allen 6 Elementen von `street.field_ids` wird in der inneren ``for``-Schleife der selbe Wert zugewiesen. So dass dort am Ende des gesamten Ablaufs die Feld-ID des letzten Feld/Strasse-Paars 6 mal steht das zuletzt durch die äusseren Schleifen gefunden wurde, und alle vorherigen überschreibt. In Python ist das überschreiben eines Dummy-Wertes in einer Liste aber wie gesagt sowieso unüblich. Statt eine Liste mit x Dummywerten zu erstellen und die dann der Reihe nach mit den tatsächlichen Werten zu ersetzen, fängt man in Python mit einer leeren Liste an und hängt dort der Reihe nach die tatsächlichen Werte an.

Bevor man das jetzt mit den IDs für Felder und Strassen weiterverfolgt, sollte man sich überlegen diese Indirektion zu beseitigen und gleich die Objekte als Werte zu verwenden. Das macht die Datenstruktur und den Code der damit arbeiten muss, einfacher, weil man sich bei jedem Zugriff einen Zwischenschritt über die ID sparen kann.

Hier gibt's keine MoinMoin-Wikisyntax, ist ja kein MoinMoin-Wiki. ;-) Die Syntax hier im Forum ist BBCode.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn ich Dich richtig verstanden habe, willst Du die Zuordnung feld -> strasse invertieren nach strasse -> felder. Wenn mal also eine Liste mit Feldern fields hätte, wobei jedes Feld ein Attribut street hat, das beschreibt, welche Straße durch das Feld läuft und auch eine Liste streets mit allen Straßen hätte, dann könnte man das Attribut fields einer Straße so füllen:

Code: Alles auswählen

for street in streets:
    street.fields = [field for field in fields if field.street == street]
buzi
User
Beiträge: 2
Registriert: Samstag 30. Juli 2016, 09:32

Besten Dank, dass ihr euch mit meiner Anfrage beschäftigt habt.
Wie gesagt, ich habe gerade angefangen, Programmieren zu lernen, und da das alleinige Durcharbeiten von Lehrbüchern auf die Dauer nur ermüdend ist, habe ich mir als Aufgabe gestellt, irgendwann einmal mit Python ein Programm fertig zu stellen, das auch schwierigere (9x9-)str8ts lösen kann.
Meine Python-Kenntnisse stammen fast ausschließlich aus Thomas Theis’ Buch "Einstieg in Python, Ideal für Programmieranfänger geeignet", das seinem Titel auch gerecht wird.
Selbstverständlich habe ich mir zunächst Gedanken über die Datenstruktur gemacht und bin basierend auf genanntem Buch auf Arrays mit Indexierung gekommen. Die von euch vorgeschlagenen Attribute und namedtupel scheinen mir nach kurzer heutiger Recherche für mich interessant zu sein, kommen in dem Buch aber nicht vor, daher die Indizes.
Aus meiner Anfrage ging nicht hervor:
Es gibt ein Array für die Felder namens fe mit den "Eigenschaften"
- Feldnummer
- Trennfeld (oder nicht)
- bekannte Zahl im Feld
- waagerechte Straße, in der das Feld liegt
- senkrechte Straße, in dem das Feld liegt
- Nummer der Zeile, in der das Feld liegt
- Nummer der Spalte, in der das Feld liegt
- mögliche Zahlen in dem Feld
Es gibt ein Array namens stze für die Straßen der Zeilen (st für Straße, ze für Zeile) mit den "Eigenschaften"
- Straßennummer (für alle möglichen Straßen, also je Zeile 3)
- Straße existiert (oder nicht)
- Zeilennummer
- Spaltennummer
- Straßenlänge
- enthaltene Felder
- bekannte Zahlen
- ein paar andere Eigenschaften, von denen ich anfangs annahm, sie zu benötigen, wo ich jetzt aber sehe, dass sie entfallen können.
Es gibt ein Array namens stsp mit den Straßen der Spalten mit derselben Struktur. (Die Aufteilung der Straßen in zwei Array hat sich als sehr praktisch erwiesen, so haben gleiche Eigenschaften bei beiden Straßenarten die selben Bezeichnungen.)
Außerdem hatte ich noch ein Array für Eigenschaften der Zeilen und ein gleich aufgebautes für die Spalten aufgebaut, wobei ich bisher noch keine darin enthaltenen Daten benötigt habe, si können wohl entfallen.
Mir war klar, dass sich die Datenstruktur im Laufe meines Lernens einige Male ändern wird. Um den Aufwand dafür nicht unnötig groß werden zu lassen, habe ich mit einem 6x6str8ts angefangen. Gerade heute bin ich soweit gekommen, dass mein Programm dieses Str8ts löst. Der Programmcode wird Insidern sicher die Haare zu Berge stehen lassen, aber ich werde ihn verbessern, sobald ich etwas dazugelernt habe, das das ermöglicht. Denn mein erstes Ziel ist Python und damit etwas Programmieren zu lernen, und erst mein zweite ist, einen funktionierenden str8tssolver zu haben.
Übrigens: Dass die Arrey-Bezeichnungen so kurz sind, stört mich nicht, an die habe ich mich längst gewöhnt. Und die Kürze ist praktisch, weil ich die Bezeichnungen häufig schreiben muss. Wenn ich allerdings durch Verwendung von namedtupel und Attributen um die wirklich nicht gehirnkompatiblen Indizes drumrum komme, wäre mir das sehr recht.
Bevor ich jetzt mit dem 9x9str8ts beginne, werde ich mich schlau machen bezüglich namedtupel und Attribute. Habe mir kürzlich das Handbuch von Ernesti/Kaiser zugelegt, da steht ist das erläutert. Eure Anregungen kommen also gerade zur rechten Zeit, besten Dank.
BlackJack

@buzi: Listen sind keine Arrays. Bitte den Satz 100× an die Tafel schreiben. :-) Ernsthaft: gute, passende Namen sind wichtig, und Arrays sind etwas anderes als Listen. Es ist verwirrend das Du da immer Arrays zu sagst. Mit dem Datentyp Array ist in Python in 99% der Fälle der Datentyp von Numpy gemeint.

Das die kurzen Namen für Deine Listen Dich nicht stören ist egal, denn andere Leser stören sie, weil man dadurch das Programm schwerer verstehen kann. Anderer Leser sind zum Beispiel wir, aber auch *Du selbst*. Nämlich wenn Du Dich da nach einem halben Jahr wieder versuchst rein zu lesen. Die Länge beim Tippen guter Namen ist kein Argument, denn erstens wird Quelltext öfter gelesen als geschrieben, selbst von dem der ihn schreibt, und da sollte nicht kurz, sondern verständlich das Kriterium sein, und zweitens bieten selbst einfache Editoren eine Autovervollständigung, mindestens auf Grundlage der offenen Datei(en), so dass man die Namen nicht immer komplett tippen muss.
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Wobei man kurze Namen nicht in allen Fällen verteufeln sollte. Allerdings sollte deren Bedeutung in allem Fällen sofort klar sein.

Beispiele seien hier x, y, z für numerische Werte, xs, ys, zs für Sequenzen von numerischen Werten, f, g, h für Funktionen, i, j für Indizes etc, in list-comprehensions oder Generatorausdrücke.

Gerne verwende ich auch e für ein einzelnes Element in einer for-Schleife. Wobei der Schleifenblock nie mehr als drei oder vier Zeilen lang ist.

Wobei ich aber nie Namen abkürze. Hier verwirrt das spätestens, wenn man den Code nach einem halben Jahr nochmal ansehen muss.

Alles IMHO ;)
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Antworten