Dictionary start point

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
eli
User
Beiträge: 6
Registriert: Mittwoch 28. September 2022, 15:01

Code: Alles auswählen

{
    1: {
        1: {
            "name": "The Vanishing of Will Byers",
            "duration": 49},
        2: {
            "name": "The Weirdo on Maple Street",
            "duration": 56}
    },
    2: {
        1: {
            "name": "MADMAX", 
            "duration": 48},
        2: {
            "name": "Trick or Treat, Freak", 
            "duration": 57},
        3: {
            "name": "The Pollywog", 
            "duration": 51}
    },
}
Wie kann ich zb jetzt im dictionary bei Staffel 1 Episode 2 anfangen und dann meine Funktion laufen lassen, bis die Zeit abgelaufen ist.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du aufsteigend nummerierte Indizes in Woerterbuechern benutzt, benutzt du die falsche Datenstruktur. Denn das sollte dann eine Liste sein. Also in deinem Fall eine Liste mit Listen darin, die jeweils ein Film-Woerterbuch enthalten.

Der Zugriff auf die Laenge von Episode zwei von Staffel ist dann einfach

Code: Alles auswählen

series[1][1]['duration']
Was du mit "Funktion laufen lassen, bis die Zeit abgelaufen ist" meinst, musst du mal ausfuehren. Dafuer gibt es keine allgemeine Antwort.
Benutzeravatar
__blackjack__
User
Beiträge: 14069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eli: Da fehlt irgendwie Kontext bei der Frage. So ganz allgemein musst Du halt die Information die Du hast, also Staffel- und Episodennummer verwenden um an die Daten von der gewünschten Episode zu kommen, und dort dann die Dauer abfragen. Das sind Grundoperationen auf Wörterbüchern die in jedem Grundlagentutorial erklärt werden. Ein brauchbares Grundlagentutorial ist in der Python-Dokumentation zu finden. Das sollte man IMHO mal durchgearbeitet haben.

Eine Funktion kann man von aussen nicht wirklich abbrechen, das muss also *in* der Funktion geregelt werden. Indem man beispielsweise regelmässig schaut wie viel Zeit vergangen ist. `time.monotonic()` und Grundrechenarten helfen da. Falls das eine ”busy loop” wird, sollte man mit einem geeigneten Wert und `time.sleep()` dafür sorgen, dass das nicht 100% CPU-Last verursacht. Falls man in der Funktion irgend etwas aufruft was ein `timeout` in irgendeiner Form hat, kann man auch davon Gebrauch machen.

@__deets__: Listen von Listen funktioniert natürlich nur wenn die Daten vollständig sind.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
eli
User
Beiträge: 6
Registriert: Mittwoch 28. September 2022, 15:01

__deets__ hat geschrieben: Donnerstag 17. November 2022, 11:42 Wenn du aufsteigend nummerierte Indizes in Woerterbuechern benutzt, benutzt du die falsche Datenstruktur. Denn das sollte dann eine Liste sein. Also in deinem Fall eine Liste mit Listen darin, die jeweils ein Film-Woerterbuch enthalten.

Der Zugriff auf die Laenge von Episode zwei von Staffel ist dann einfach

Code: Alles auswählen

series[1][1]['duration']
Was du mit "Funktion laufen lassen, bis die Zeit abgelaufen ist" meinst, musst du mal ausfuehren. Dafuer gibt es keine allgemeine Antwort.
Am ende sollte die Funktion mit den Parametern (season: dict, start: tuple[int, int], binge_time: int) ab dem Startwert das woerterbuch durchgehen (also die Episoden) bis eben die "binge_time" < "Laenge der Episode" ist.

haette das so gemacht?:

Code: Alles auswählen

    if time_left >= episode_duration:
        print(f'Watched Season {season_number} Episode {episode_number}: "{episode_name}", {time_left} minutes' 
        'left to binge!')
    else:
        print(f'No more full episodes today! Only {time_left} minutes are left to watch, '
        'but Season {season_number} Episode {episode_number}: "{episode_name}" has {episode_duration} minutes.')
        print(f'{num_episodes_watched} episode(s) watched today.')
allerdings bin ich draufgekommen das ich nicht wie gedacht auf das dictionary zugreifen kann und mir die einzelnen Parameter herausnehmen kann:
meine ueberlegungne waren:

Code: Alles auswählen

    for season_number in season:
        season_dict = season[season_number]

    for episode_number in season_dict:
        episod_dict = season_dict[episode_number]
    
    for name, duration in episod_dict:
        episode_name = episod_dict[name]
        episode_duration = episod_dict[duration]
gibt es also ueberhaupt so eine moeglichkeit, oder bin ich auf einem komplett falschen weg? (sorry fuer den code habe erst vor einer woche angefangen zu programmieren)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist immer noch sehr verwirrend. Zugriff auf Schluessel in einem Woerterbuch muessen schon wirklich die Schluessel sein, nicht unbekannte Namen:

Code: Alles auswählen

d = { "schluessel": "wert"}
d["schluessel"] # geht
d[schluessel] # geht nicht, schluessel gibt es nicht
schluessel = "foobar"
d[schluessel] # geht auch nicht wirklich, weil KeyError
Wenn du die Schluessel kennst (so wie hier), dann sind wahlweise Strings die Antwort, oder Konstanten, also

Code: Alles auswählen

DURATION = "duration"
...
episode_duration = episode[DURATION]  # NICHT den Datentyp in den Variablennamen schreiben! Das ist jetzt ein dict, mag aber viel sinnvoller eine Datenklasse sein, und dann stimmt das nicht mehr!!!
eli
User
Beiträge: 6
Registriert: Mittwoch 28. September 2022, 15:01

Erforderliche Funktion: stranger_binger
Funktionsweise:
Schreiben Sie eine Funktion stranger_binger, welche drei Parameter übernimmt. Der erste Parameter seasons ist ein Dictionary, das beliebig viele Staffel-Dictionaries und in diesen wiederum die jeweiligen Episoden-Informationen als Dictionary enthält. Jedes Episoden-Dictionary enthält Informationen über den Namen der Episode (episode_name als key) und ihre Spieldauer (duration als key) in Minuten.
Die Staffeln und jeweiligen Episoden werden im seasons-Dictionary mit Ganzzahlen-keys in aufsteigender Reihenfolge von 1 bis \(n\) (=so viele es gibt) identifiziert.
Das Dictionary ist also wie folgt aufgebaut:

Code: Alles auswählen

{
    1: {
        1: {
            "name": "<name_1_1>",
            "duration": <duration_1_1>
        },
        2: {
            "name": "<name_1_2>",
            "duration": <duration_1_2>
        },

        ...

        <m>: {
            "name": "<name_1_m>",
            "duration": <duration_1_m>
        }
    },

    ...

    <n>: {
        1: {
            "name": "<name_n_1>",
            "duration": <duration_n_1>
        },

        ...
    }
}
Der zweite Parameter der Funktion (start) enthält ein Tuple mit zwei Zahlen (ab hier n und m genannt). Die erste Zahl repräsentiert die Nummer der Staffel (n) und die zweite Zahl die Nummer der Episode (m) mit der Sie in dieser Binge-Session weitermachen möchten. Mit dem dritten Parameter binge_time geben Sie an, wie viel Zeit (in Minuten) sie maximal für Ihre Binge-watching-Session zur Verfügung haben.

Sie beginnen somit mit der in start angegebenen Staffel (n) und Episode (m) und sehen sich die Episoden in aufeinanderfolgender Reihenfolge bis zum Erschöpfen ihrer Zeit (binge_time) an. Nach jeder finalisierten Episode soll die noch verbleibende Zeit ausgegeben werden:

Watched Season <season_number> Episode <episode_number>: "<episode_name>", <time_left> minutes left to binge!
Falls das Schauen einer Episode ihre Zeit (binge_time) erschöpfen würde, printen Sie:

No more full episodes today! Only <time_left> minutes are left to watch, but Season <season_number> Episode <episode_number>: "<episode_name>" has <episode_duration> minutes.
und hören auf zu schauen.
Geben Sie zusätzlich die Info, wie viele Episoden Sie heute gesehen haben, in folgenden Format aus:

<num_episodes_watched> episode(s) watched today.
Wenn Sie die Serie nicht zu Ende sehen konnten, weil keine Zeit mehr blieb, geben Sie per return zurück, bei welcher Staffel und Episode Sie aufgehört haben. Diese Information soll als Tupel (<Staffelnummer>, <Episodennummer>) zurückgegeben werden. Wenn Sie alle Staffeln und Episoden sehen konnten, geben Sie stattdessen None zurück.

Beispiel:

Ein seasons-dictionary

Code: Alles auswählen

{
    1: {
        1: {
            "name": "The Vanishing of Will Byers",
            "duration": 49},
        2: {
            "name": "The Weirdo on Maple Street",
            "duration": 56}
    },
    2: {
        1: {
            "name": "MADMAX", 
            "duration": 48},
        2: {
            "name": "Trick or Treat, Freak", 
            "duration": 57},
        3: {
            "name": "The Pollywog", 
            "duration": 51}
    },
}
mit start-Episode (1, 2) und einer binge_time von 142 Minuten ergibt die Ausgabe

Watched Season 1 Episode 2: "The Weirdo on Maple Street", 86 minutes left to binge!
Watched Season 2 Episode 1: "MADMAX", 38 minutes left to binge!
No more full episodes today! Only 38 minutes are left to watch, but Season 2 Episode 2: "Trick or Treat, Freak" has 57 minutes.
2 episode(s) watched today.
und gibt (2, 2) zurück.
Benutzeravatar
__blackjack__
User
Beiträge: 14069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eli: Deine drei ``for``-Schleifenbeispiele sind etwas sinnfrei, insbesondere das letzte. Wenn man über die Schlüssel iteriert um die dann zu verwenden um auf den Wert zuzugreifen, könnte man auch gleich über die Werte iterieren (`values()`) und den Schlüssel ignorieren, oder falls man beides braucht gleich über beides iterieren (`items()`).

Ich wäre bei Wörterbüchern vorsichtig was die Reihenfolge angeht, denn die sind ja nicht automatisch aufsteigend nach Schlüssel sortiert. Das würde ich hier lieber noch mal explizit sortieren um sicher zu gehen. Und wenn Du Episoden ab einer bestimmten Nummer willst, musst Du sowieso eine Sequenz aus den Daten erstellen und dann erst alle Episoden mit kleineren nummern überspringen, denn eine „gib mir alle Schlüssel/Wert-Paare ab einem bestimmten Schlüssel“ gibt es nicht als `dict`-Operation.

Als erstes würde man hier also die komplette Datenstruktur ”flachklopfen”, so dass man die Staffel, Episode, und den Rest als jeweils ein Datum hat. Das nach Staffel und Episode sortiert. Dann übergeht man alle die kleiner als der Startwert sind. Und nimmt dann Episoden solange die Zeit nicht überschritten wird.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
__blackjack__
User
Beiträge: 14069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Nicht weiter getestet als hier zu sehen ist:

Code: Alles auswählen

#!/usr/bin/env python3
from itertools import dropwhile

from attrs import field, frozen

SEASONS_DATA = {
    1: {
        1: {"name": "The Vanishing of Will Byers", "duration": 49},
        2: {"name": "The Weirdo on Maple Street", "duration": 56},
    },
    2: {
        1: {"name": "MADMAX", "duration": 48},
        2: {"name": "Trick or Treat, Freak", "duration": 57},
        3: {"name": "The Pollywog", "duration": 51},
    },
}


@frozen(order=True)
class Numbers:
    season = field()
    episode = field()

    def __str__(self):
        return f"Season {self.season} Episode {self.episode}"


@frozen(order=True)
class Episode:
    numbers = field()
    name = field()
    duration = field()

    def __str__(self):
        return f"{self.numbers}: {self.name}"


def create_episodes(seasons_data):
    return sorted(
        Episode(
            Numbers(season_number, episode_number),
            episode_data["name"],
            episode_data["duration"],
        )
        for season_number, season_data in seasons_data.items()
        for episode_number, episode_data in season_data.items()
    )


def binge(episodes, start, binge_time):
    watched_episode_count = 0
    for episode in dropwhile(
        lambda episode: episode.numbers < start, episodes
    ):
        if episode.duration > binge_time:
            print(
                f"No more full episodes today! Only {binge_time} minutes are"
                f" left to watch, but {episode} has"
                f" {episode.duration} minutes."
            )
            break

        watched_episode_count += 1
        binge_time -= episode.duration
        print(f"Watched {episode}, {binge_time} minutes left to binge!")
    else:
        episode = None

    print(f"{watched_episode_count} episode(s) watched today.")

    return episode.numbers if episode else None


def main():
    print(repr(binge(create_episodes(SEASONS_DATA), Numbers(1, 2), 142)))


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten