Verdammt, war zu langsam. Bitte die Schnittmenge mit dem Beitrag von Sirius3 einfach ignorieren.
@cbesi: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassennamen (PascalCase). Und das es eine Klasse ist, gehört nicht in den Namen.
Die Klassenattribute `first` und `second` gehören dort nicht hin. Werden auch nirgends verwendet. Klassenattribute sind in der Regel Konstanten, weil Variablen an der Stelle globaler Zustand ist, den man vermeidet.
Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. `f` und `s` für `first` und `second` ist alles andere als selbsterklärend. Wobei auch bei `first` und `second` niemand anhand der Namen darauf kommt, dass es sich um einen Namen einer Waage und ein ermitteltes Gewicht handelt. Letztlich wird die Klasse aber gar nicht wirklich verwendet.
Namen nummeriert man nicht. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen und -werte, sondern eine Datenstruktur. Oft, und so auch im Fall von `gewichte`, eine Liste. Und auch wirklich eine Liste und das nicht nur im Kommentar schreiben, dann aber ein Tupel anlegen.
Auf Modulebene sollte nur Code stehen, der Konstanten, Funktionen, und Klassen definiert. Das Hauptrogramm steht üblicherweise in einer Funktion die `main()` heisst.
Kommentare sollten dem Leser einen Mehrwert über den Code bieten. Faustregel: Ein Kommentar beschreibt nicht was der Code macht, denn das steht dort bereits als Code, sondern warum er das so macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in der Regel was in der Dokumentation von Python oder den verwendeten Bibliotheken steht.
Besonders schlecht sind Kommentare die inhaltlich falsch sind. Dann weiss der Leser nicht ob der Kommentar oder der Code fehlerhaft ist. So ein Kommentar wirft also Fragen auf, statt welche zu klären. Das Gegenteil von dem wofür man Kommentare schreibt.
Wenn im Kommentar was von Liste steht, der Code aber ein Tupel verwendet, oder im Kommentar „dict comprehension“ steht, im Code dazu aber gar keine „comprehension“-Syntax steht, oder im Kommentar `max()` steht, im Code dann aber `min()`, dann ist das sehr schlecht. Schlechter als kein Kommentar.
`print()` kann man mehrere Argumente übergeben. Die werden mit Leerzeichen getrennt ausgegeben und jeder Wert wird von `print()` in eine Zeichenkette umgewandelt. Auch ausserhalb von `print()` ist zusammenstückeln von Zeichenketten und Werten mit `str()` und ``+`` eher BASIC als Python. Python hat dafür die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.
`res` ist kein guter Name, weil abgekürzt und völlig nichtssagend, und es wird im gleichen Namensraum für zwei völlig unterschiedliche Datenstrukturen verwendet.
Anstelle eines Wörterbuchs würde man auch besser ein `collections.defaultdict()` verwenden.
Auch alles mögliche `ele` nennen hat wieder die drei Probleme 1) kryptische Abkürzung, 2) nichtssagender Name, und 3) man muss so verdammt aufpassen wann welcher Wert/Typ an diesen Namen gebunden ist.
Also das Original mal überarbeitet:
Code: Alles auswählen
#!/usr/bin/env python3
from collections import defaultdict
from itertools import combinations
def main():
gewichte = [10, 15, 15, 20, 20, 18, 25, 30]
soll_gewicht = 48
print("The original weights are:", gewichte)
gesamtgewicht_auf_gewichtspaare = defaultdict(list)
for gewichtspaar in combinations(gewichte, 2):
gesamtgewicht_auf_gewichtspaare[sum(gewichtspaar)].append(gewichtspaar)
gewichtspaare_mit_kleinster_abweichung = gesamtgewicht_auf_gewichtspaare[
min(
gesamtgewicht_auf_gewichtspaare.keys(),
key=lambda gesamtgewicht: abs(gesamtgewicht - soll_gewicht),
)
]
print("The closest sum pairs are:", gewichtspaare_mit_kleinster_abweichung)
if __name__ == "__main__":
main()
Wenn man jetzt nicht nur die Gewichte sondern auch die Waagen braucht, müsste man Waage und Gewicht zu einem Objekt zusammenfassen. Da kann eine Klasse oder ein mit `collections.namedtuple()` erstellter Datentyp Sinn machen.
Man muss die einzelnen Schritte dann entsprechend anpassen.
Code: Alles auswählen
#!/usr/bin/env python3
from collections import defaultdict, namedtuple
from itertools import combinations
Waegung = namedtuple("Waegung", "waagenname gewicht")
def main():
waegungen = [
Waegung(f"Waage{i}", gewicht)
for i, gewicht in enumerate([10, 15, 15, 20, 20, 18, 25, 30], 1)
]
soll_gewicht = 48
print("The original weights are:", waegungen)
gesamtgewicht_auf_waegungspaare = defaultdict(list)
for waegungspaar in combinations(waegungen, 2):
gesamtgewicht = sum(waegung.gewicht for waegung in waegungspaar)
gesamtgewicht_auf_waegungspaare[gesamtgewicht].append(waegungspaar)
waegungspaare_mit_kleinster_abweichung = gesamtgewicht_auf_waegungspaare[
min(
gesamtgewicht_auf_waegungspaare.keys(),
key=lambda gesamtgewicht: abs(gesamtgewicht - soll_gewicht),
)
]
print("The closest sum pairs are:", waegungspaare_mit_kleinster_abweichung)
if __name__ == "__main__":
main()