Re: Alle Permutationen mehrerer Listen mit Wiederholungen, aber mit bestimmten Voraussetzungen
Verfasst: Sonntag 26. Mai 2019, 16:17
von hohlinger
Und die Ausgabe:
('Sollwert:', 66)
('Gewürfelte Werte:', 1, 2, 3)
------------------------------
1: ('+', '+')
2: ('+', '-')
3: ('+', '*')
4: ('+', '/')
5: ('-', '+')
6: ('-', '-')
7: ('-', '*')
8: ('-', '/')
9: ('*', '+')
10: ('*', '-')
11: ('*', '*')
12: ('*', '/')
13: ('/', '+')
14: ('/', '-')
15: ('/', '*')
16: ('/', '/')
1: (1, 2, 3)
2: (1, 3, 2)
3: (2, 1, 3)
4: (2, 3, 1)
5: (3, 1, 2)
6: (3, 2, 1)
7: (10, 20, 30)
8: (10, 30, 20)
9: (20, 10, 30)
10: (20, 30, 10)
11: (30, 10, 20)
12: (30, 20, 10)
13: (100, 200, 300)
14: (100, 300, 200)
15: (200, 100, 300)
16: (200, 300, 100)
17: (300, 100, 200)
18: (300, 200, 100)
19: (1, 10, 100)
20: (1, 10, 200)
21: (1, 10, 300)
22: (1, 20, 100)
23: (1, 20, 200)
24: (1, 20, 300)
25: (1, 30, 100)
26: (1, 30, 200)
27: (1, 30, 300)
28: (2, 10, 100)
29: (2, 10, 200)
30: (2, 10, 300)
31: (2, 20, 100)
32: (2, 20, 200)
33: (2, 20, 300)
34: (2, 30, 100)
35: (2, 30, 200)
36: (2, 30, 300)
37: (3, 10, 100)
38: (3, 10, 200)
39: (3, 10, 300)
40: (3, 20, 100)
41: (3, 20, 200)
42: (3, 20, 300)
43: (3, 30, 100)
44: (3, 30, 200)
45: (3, 30, 300)
46: (1, 100, 10)
47: (1, 100, 20)
48: (1, 100, 30)
49: (1, 200, 10)
50: (1, 200, 20)
51: (1, 200, 30)
52: (1, 300, 10)
53: (1, 300, 20)
54: (1, 300, 30)
55: (2, 100, 10)
56: (2, 100, 20)
57: (2, 100, 30)
58: (2, 200, 10)
59: (2, 200, 20)
60: (2, 200, 30)
61: (2, 300, 10)
62: (2, 300, 20)
63: (2, 300, 30)
64: (3, 100, 10)
65: (3, 100, 20)
66: (3, 100, 30)
67: (3, 200, 10)
68: (3, 200, 20)
69: (3, 200, 30)
70: (3, 300, 10)
71: (3, 300, 20)
72: (3, 300, 30)
73: (10, 1, 100)
74: (10, 1, 200)
75: (10, 1, 300)
76: (10, 2, 100)
77: (10, 2, 200)
78: (10, 2, 300)
79: (10, 3, 100)
80: (10, 3, 200)
81: (10, 3, 300)
82: (20, 1, 100)
83: (20, 1, 200)
84: (20, 1, 300)
85: (20, 2, 100)
86: (20, 2, 200)
87: (20, 2, 300)
88: (20, 3, 100)
89: (20, 3, 200)
90: (20, 3, 300)
91: (30, 1, 100)
92: (30, 1, 200)
93: (30, 1, 300)
94: (30, 2, 100)
95: (30, 2, 200)
96: (30, 2, 300)
97: (30, 3, 100)
98: (30, 3, 200)
99: (30, 3, 300)
100: (10, 100, 1)
101: (10, 100, 2)
102: (10, 100, 3)
103: (10, 200, 1)
104: (10, 200, 2)
105: (10, 200, 3)
106: (10, 300, 1)
107: (10, 300, 2)
108: (10, 300, 3)
109: (20, 100, 1)
110: (20, 100, 2)
111: (20, 100, 3)
112: (20, 200, 1)
113: (20, 200, 2)
114: (20, 200, 3)
115: (20, 300, 1)
116: (20, 300, 2)
117: (20, 300, 3)
118: (30, 100, 1)
119: (30, 100, 2)
120: (30, 100, 3)
121: (30, 200, 1)
122: (30, 200, 2)
123: (30, 200, 3)
124: (30, 300, 1)
125: (30, 300, 2)
126: (30, 300, 3)
127: (100, 1, 10)
128: (100, 1, 20)
129: (100, 1, 30)
130: (100, 2, 10)
131: (100, 2, 20)
132: (100, 2, 30)
133: (100, 3, 10)
134: (100, 3, 20)
135: (100, 3, 30)
136: (200, 1, 10)
137: (200, 1, 20)
138: (200, 1, 30)
139: (200, 2, 10)
140: (200, 2, 20)
141: (200, 2, 30)
142: (200, 3, 10)
143: (200, 3, 20)
144: (200, 3, 30)
145: (300, 1, 10)
146: (300, 1, 20)
147: (300, 1, 30)
148: (300, 2, 10)
149: (300, 2, 20)
150: (300, 2, 30)
151: (300, 3, 10)
152: (300, 3, 20)
153: (300, 3, 30)
154: (100, 10, 1)
155: (100, 10, 2)
156: (100, 10, 3)
157: (100, 20, 1)
158: (100, 20, 2)
159: (100, 20, 3)
160: (100, 30, 1)
161: (100, 30, 2)
162: (100, 30, 3)
163: (200, 10, 1)
164: (200, 10, 2)
165: (200, 10, 3)
166: (200, 20, 1)
167: (200, 20, 2)
168: (200, 20, 3)
169: (200, 30, 1)
170: (200, 30, 2)
171: (200, 30, 3)
172: (300, 10, 1)
173: (300, 10, 2)
174: (300, 10, 3)
175: (300, 20, 1)
176: (300, 20, 2)
177: (300, 20, 3)
178: (300, 30, 1)
179: (300, 30, 2)
180: (300, 30, 3)
Hier sind eben immer noch die Möglichkeiten mit den Wiederholungen der Vielfachen drin, z.B. (300, 30, 3). Über die weitere Behandlung habe ich mir noch keine Gedanken gemacht, ich möchte zunächst eine korrekte Ausgabe der 162 Möglichkeiten.
Vielen Dank im Voraus für Eure Hilfe.
Re: Alle Permutationen mehrerer Listen mit Wiederholungen, aber mit bestimmten Voraussetzungen
Verfasst: Sonntag 26. Mai 2019, 18:48
von __blackjack__
@hohlinger: Man sollte heute keine Programme mehr mit Python 2 anfangen.
``print`` ist in Python 2 eine Anweisung und keine Funktion, da gehören also keine Klammern um die ”Argumente” die ja keine sind. Sieht man auch schön an den ersten beiden Ausgaben, wo Du genau *einen* Wert ausgibst, nämlich ein Tupel.
In Python 2 sollte man kein `input()` verwenden sondern `raw_input()` und die Eingabe dann explizit in einen anderen Datentyp umwandeln. `input()` führt beliebige Python-Ausdrücke aus, die der Benutzer eingibt. Hatte ich schon erwähnt das man kein Python 2 mehr verwenden sollte?
Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Konstanten schreibt man KOMPLETT_GROSS.
Importe gehören an den Anfang des Moduls. Gefolgt von Konstanten.
`zahl1` ist ein blöder Name. Total nichtssagend und eine überflüssige 1. Namen sollte man sowieso nicht nummerieren. Das ist in der Regel ein Zeichen das man sich bessere Namen ausdenken sollte oder eine Datenstruktur verwenden sollte. Oft ist das eine Liste.
Zu `zahl1`: Wenn das der Sollwert ist, wäre `sollwert` ein guter Name.
Und für `w1` bis `w3` wäre eine Liste geeigneter als Einzelnamen. Du packst Die Ergebnisse ja am Ende sowieso in eine Liste, warum also nicht gleich von Anfang an. Dann hätte man schon mal `a`. `b` und `c` lassen sich daraus berechnen. Und man sollte das nicht an einzelne Namen binden, sondern das ist doch auch wieder eine Liste.
Grunddatentypen gehören nicht in Namen. Wenn man den Datentyp im Laufe der Programmentwicklung ändert, muss man dann überall die betroffenen Namen ändern, oder man hat falsche und irreführende Namen im Quelltext stehen.
Man sollte auch keine Abkürzungen verwenden. Der Leser soll nicht raten müssen ob mit `rech` nun `rechenart`, `rechensymbol`, oder was ganz anderes gemeint ist.
Die ganzen `list()`-Aufrufe sind überflüssig. Das schöne an den Iteratoren auf die Du das anwendest ist ja gerade das die keine Liste mit allen Ergebnissen erstellen, sondern jedes Element erst dann erzeugen wenn man es anfragt. Und Du sammelst die Werte alle in Listen ohne tatsächlich jemals die komplette Liste auf einmal zu benötigen.
Wenn man zusätzlich zu einem iterarierbaren Objekt noch eine laufende Zahl benötigt, gibt es `enumerate()`. Da muss man sich nicht selbst einen über den Code verteilten Zähler basteln.
Zeichenkettenliterale und Werte mit `str()` und ``+`` zusammenstückeln ist eher BASIC als Python. In Python verwendet man dafür Zeichenkettenformatierung mit der `format()`-Methode auf Zeichenketten.
Das mit dem ``i = 1`` und ``i += 1`` ist auch ziemlich nervig. Diesen Code würde man besser in eine Printfunktion kapseln die automatisch nummerierte Ausgaben erzeugt.
Der `entry_`-Präfix ist irreführend wenn man die überflüssigen Listen weg lässt, denn Iteratoren haben keine ”Einträge”. Der Präfix bringt aber auch mit Listen nicht wirklich einen Mehrwert.
Zwischenergebnis:
Code: Alles auswählen
#!/usr/bin/env python3
from itertools import count, permutations, product
LINIE = '-' * 30
def create_numbering_print(start=1):
numbers = count(start)
def numbering_print(*args, **kwargs):
print('{}:'.format(next(numbers)), *args, **kwargs)
return numbering_print
def main():
sollwert = int(input('Bitte eine Zahl zwischen 1 und 99 eingeben: '))
wuerfelergebnisse = [
int(input('Würfel {}: '.format(i))) for i in range(1, 4)
]
print('Sollwert:', sollwert)
print('Gewürfelte Werte:', wuerfelergebnisse)
print()
print(LINIE)
print()
multiplizierte_wuerfelergebnisse = [
[w * 10**e for w in wuerfelergebnisse] for e in range(3)
]
a, b, c = multiplizierte_wuerfelergebnisse
rechensymbole = ['+', '-', '*', '/']
for i, rechensymbol in enumerate(product(rechensymbole, repeat=2), 1):
print('{}: {}'.format(i, rechensymbol))
# mögliche Kombinationen der Würfelergebnisse:
print(LINIE)
numbering_print = create_numbering_print()
for permutation in permutations(a):
numbering_print(permutation)
for permutation in permutations(b):
numbering_print(permutation)
for permutation in permutations(c):
numbering_print(permutation)
# Kreuzprodukte aus a, b und c:
print(LINIE)
numbering_print = create_numbering_print()
for kreuzabc in product(a, b, c):
numbering_print(kreuzabc)
for kreuzacb in product(a, c, b):
numbering_print(kreuzacb)
for kreuzbac in product(b, a, c):
numbering_print(kreuzbac)
for kreuzbca in product(b, c, a):
numbering_print(kreuzbca)
for kreuzcab in product(c, a, b):
numbering_print(kreuzcab)
for kreuzcba in product(c, b, a):
numbering_print(kreuzcba)
if __name__ == '__main__':
main()
Ich habe hier die Namen `a`, `b`, und `c` gelassen, aber diese Einzelwerte sind ja genau der Grund warum Du da so verdammt viel schreiben bzw. kopieren und einfügen musstest. Bei den Kreuzprudukten der einzelnen Listen ist das ganz einfach durch eine Schleife über `multiplizierte_wuerfelergebnisse` lösbar, denn die Liste enthält `a`, `b`, und `c` ja als Elemente.
Bei den letzten sechs ``for``-Schleifen hast Du von Hand die Permutationen gebildet – dafür gibt es doch `permutations()`.
Code: Alles auswählen
#!/usr/bin/env python3
from itertools import count, permutations, product
LINIE = '-' * 30
def create_numbering_print(start=1):
numbers = count(start)
def numbering_print(*args, **kwargs):
print('{}:'.format(next(numbers)), *args, **kwargs)
return numbering_print
def main():
sollwert = int(input('Bitte eine Zahl zwischen 1 und 99 eingeben: '))
wuerfelergebnisse = [
int(input('Würfel {}: '.format(i))) for i in range(1, 4)
]
print('Sollwert:', sollwert)
print('Gewürfelte Werte:', wuerfelergebnisse)
print()
print(LINIE)
print()
multiplizierte_wuerfelergebnisse = [
[w * 10**e for w in wuerfelergebnisse] for e in range(3)
]
rechensymbole = ['+', '-', '*', '/']
for i, rechensymbol in enumerate(product(rechensymbole, repeat=2), 1):
print('{}: {}'.format(i, rechensymbol))
# Mögliche Kombinationen der Würfelergebnisse:
print(LINIE)
numbering_print = create_numbering_print()
for multipliertes_ergebnis_pro_wuerfel in multiplizierte_wuerfelergebnisse:
for permutation in permutations(multipliertes_ergebnis_pro_wuerfel):
numbering_print(permutation)
# Kreuzprodukte aus multiplizierten Würfelergebnissen:
print(LINIE)
numbering_print = create_numbering_print()
for permutation in permutations(multiplizierte_wuerfelergebnisse):
for kreuzprodukt in product(*permutation):
numbering_print(kreuzprodukt)
if __name__ == '__main__':
main()
Ich würde ja dringend raten das in Funktionen aufzuteilen und nicht zu versuchen das alles in einem grossen klumpen Code zu lösen. Und auch keine mehrdimensionalen Datenstrukturen verwenden wenn das nicht nötig ist. Also `multiplizierte_wuerfelergebnisse` ist mir schon zu komplex als Zwischenergebnis. Ausgehend von einer Liste mit den drei Würfelergebnissen eine oder mehrere Generatorfunktionen die Zahlentripel generieren. Das geht analog zum Icon-Code auch in Python in einer Funktion mit zwei Schleifen und einer „list comprehension“. Damit kann man alle Operanden für die Rechnungen erzeugen.
Da die Würfe nicht verschieden sein müssen, im Extremfall kann man ja drei mal die gleiche Zahl würfeln, müsste man da trotzdem noch mal Duplikate raus filtern, also die generierten Zahlentripel in einem `set()` sammeln, beispielsweise, oder durch `more_itertools.unique_ever_seen()` filtern.
Und wenn man die Tripel alle hat, kann man sich eine Funktion schreiben, die daraus Ausdrücke generiert, also jeden Operanden-Satz mit den Rechenoperationen kombiniert. Spätestens hier wird dann eine Klasse interessant, wie man am Icon-Code sehen sehen kann.
In Python lohnt sich eventuell auch eine Klasse für die Rechenoperationen weil man hier nicht so wie in Icon einfach eine Zeichenkette mit dem Operatorsymbol auch als binäre Funktion verwenden kann. Die Operatoren als Funktionen kann man bei Python im `operator`-Modul finden.