Summieren einer Liste in einem Dictionary

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
sc19
User
Beiträge: 10
Registriert: Samstag 18. Dezember 2021, 15:09

Ich möchte die Punkte (points), innerhalb einer For-Schleife Summieren.
Wie man in meinem Code sehen kann, ist die Anzahl der Elemente (Einträge) in "points" unterschiedlich.
Kann mir jemand dabei helfen, das pytonisch umzusetzen?

[code
student1 = {'name': 'Hans', 'points': [285, 210, 135, 100, 300]}
student2 = {'name': 'Peter', 'points': [65, 56, 48]}

students = [student1, student2]

for stud in students:
sumpoints = stud['points'][0]+stud['points'][1]+stud['points'][2]

print(sumpoints)]
[/code]
Benutzeravatar
sparrow
User
Beiträge: 4165
Registriert: Freitag 17. April 2009, 10:28

Ich denke, sum() wird dein Problem lösen.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sc19: Ergänzende Anmerkungen: Man nummeriert keine Namen. Die werden hier ja auch gar nicht wirklich gebraucht — man kann die `students`-Datenstruktur auch einfach komplett literal hinschreiben:

Code: Alles auswählen

    students = [
        {"name": "Hans", "points": [285, 210, 135, 100, 300]},
        {"name": "Peter", "points": [65, 56, 48]},
    ]
Namen sollte man auch nicht kryptisch abkürzen. `stud` gibt es ja tatsächlich als englisches Wort und das bedeutet nicht Student.

`sumpoints` ist zwar keine Abkürzung aber eine komische Wortschöpfung. Mal vom fehlenden Unterstrich abgesehen klingen „Summenpunkte“ irgendwie schräg. Das ist eine Punkt-Summe oder besser Gesamptpunktzahl, also in Englisch so etwas wie `total_points`.

Zwischenstand bei der Berechnung/Ausgabe:

Code: Alles auswählen

    for student in students:
        print(student["name"], sum(student["points"]))
Was jetzt noch unschön ist, sind die Wörterbücher für etwas das eigentlich Objekte sind. Wörterbücher mit einem festen Satz an Schlüsseln, sind ja keine allgemeinen Abbildungen von Schlüsseln auf Werte sondern etwas spezialisierteres, wo man nur Wörterbücher verwendet wenn die Sprache nichts besseres für Verbunddatentypen bietet. Also in Python minimal so etwas wie `collections.namedtuple()`:

Code: Alles auswählen

#!/usr/bin/env python3
from collections import namedtuple

Student = namedtuple("Student", "name points")


def main():
    students = [
        Student("Hans", [285, 210, 135, 100, 300]),
        Student("Peter", [65, 56, 48]),
    ]
    for student in students:
        print(student.name, sum(student.points))


if __name__ == "__main__":
    main()
Wenn man Werte zu einem Objekt zusammenfasst, macht manchmal aber auch eine eigene Klasse Sinn, denn die Gesamptpunktzahl kann man auch als eine Eigenschaft von einem Studenten-Objekt auffassen, statt etwas das ausserhalb berechnet wird:

Code: Alles auswählen

#!/usr/bin/env python3


class Student:
    def __init__(self, name, points):
        self.name = name
        self.points = points

    @property
    def total_points(self):
        return sum(self.points)


def main():
    students = [
        Student("Hans", [285, 210, 135, 100, 300]),
        Student("Peter", [65, 56, 48]),
    ]
    for student in students:
        print(student.name, student.total_points)


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
sc19
User
Beiträge: 10
Registriert: Samstag 18. Dezember 2021, 15:09

Vielen Dank für die ausführliche Erklärung!
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Übrigens, durch Vererbung kann man die eigene Klasse auch mit dem namedtuple kombinieren und sich somit die __init__()-Methode sparen:

Code: Alles auswählen

#!/usr/bin/env python3
from collections import namedtuple

class Student(namedtuple("Student", "name points")):
    @property
    def total_points(self):
        return sum(self.points)


def main():
    students = [
        Student("Hans", [285, 210, 135, 100, 300]),
        Student("Peter", [65, 56, 48]),
    ]
    for student in students:
        print(student.name, student.total_points)


if __name__ == "__main__":
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Das ist IMHO nicht so gut weil damit `Student` tatsächlich ein Tupel ist, wegen der Vererbung und so Sachen wie eine Länge hat, iterierbar ist, und mit anderen Tupeln vergleichbar, sowohl normalen als auch anderen `NamedTupel`. Das hat man bei einem reinen `namedtuple()` zwar auch, aber da finde ich das wesentlich weniger überraschend.

Da würde ich dann eher auf das externe `attrs`-Package zugreifen wenn ich mir die triviale `__init__()` sparen möchte.

Code: Alles auswählen

#!/usr/bin/env python3
from attr import attrib, attrs


@attrs(frozen=True)
class Student:
    name = attrib()
    points = attrib()

    @property
    def total_points(self):
        return sum(self.points)


def main():
    students = [
        Student("Hans", [285, 210, 135, 100, 300]),
        Student("Peter", [65, 56, 48]),
    ]
    for student in students:
        print(student.name, student.total_points)


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten