Wochentage Mo-So Codiert (Encodieren/umrechnen/berechnen)

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
chris_adnap
User
Beiträge: 27
Registriert: Freitag 23. September 2022, 09:36

Hallo,

bin schon den ganzen Tag daran, finde aber nichts.

Habe eine Webseite, die Speichert die Angabe der ausgewählten Wochentage, als Zahl "Code"...

Mo = 1
Di = 2
Mi = 4
Do = 8
Fr = 16
Sa = 32
So =64

Wähle ich als Tag Di+Do und Sonntag aus. So wird dies als "10" (Quersumme/Summierung der Auswahl) gespeichert etc..
Also von 1 bis 127 ist alles möglich.

Diesen Weg finde ich recht praktisch.
Ich hab es mal nachgerechnet, diese Verdoppelung/Duplation Werte sollten immer eindeutig sein.

Ich habe auf der Seite versucht den JS-Code durch den Debugger laufen zu lassen, um die Stelle, welches eine Codierte Eingabe auf die Tage umrechnet, zu kommen.
Entweder gibt es diese Stelle nicht, es wird die fest hinterlegte Liste genommen oder ich übersehe etwas.

Mein Code baue ich in Python auf, aber auf eine sinnvolle Umsetzung außer...
if code = 1 == Mo
elif Code == 2 == Mo, Di
...etc,
komme ich bis jetzt nicht.

Zwar habe ich alle Codes/Kombinationen schon als ein Dict abgelegt. In diesem könnte ich den Wochentag manuell einmalig fest eintragen.
Aber ich bin mir sicher, das es da Mathematisch möglich seien muss.

Wenn es dafür schon Beispiele gibt, dann reicht auch nur ein Link.
Ich konnte dazu bisher NULL finden. Da aber bin ich mir sicher, habe ich immer falsch gesucht. Aber einen richtigen Begriff habe ich dafür bis jetzt nicht.

Nochmals zusammengefasst.
Ich habe von bei Zahlen von 1 bis 127 auf die tage zu schließen.
Bsp: 118 würde z.b. Di+Mi+Fr-So bedeuten.

Mo = 1
Di = 2
Mi = 4
Do = 8
Fr = 16
Sa = 32
So =64

Mo == 1 kann man ganz leicht raus bekommen. Prüfung auf gerade/ungerade.
Dann aber bleiben noch Di-So übrig und hier brauche ich einen Denkanstoß.

Viele Grüße
Chris
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Über die Binärdarstellung läßt sich das einfach Umwandeln. Hier wird auf die einzelnen Bits getestet:

Code: Alles auswählen

WEEKDAYS = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]

encoded_days = 56

weekdays = [
    weekday
    for idx, weekday in enumerate(WEEKDAYS)
    if encoded_days & (1 << idx)
]
chris_adnap
User
Beiträge: 27
Registriert: Freitag 23. September 2022, 09:36

Guten Abend Sirius,

was soll ich sagen. Top, kurz getestet funktioniert.
Ich muss es noch auseinander nehmen, da ich das WARUM/WIE, noch nicht verstehe :D
Aber es tut genau was es soll.

Viele Grüße
Chris
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

chris_adnap hat geschrieben: Dienstag 30. Mai 2023, 22:16 Ich muss es noch auseinander nehmen, da ich das WARUM/WIE, noch nicht verstehe :D
Dann schau dir mal den Teil an, der die zu prüfenden Werte erzeugt. Wenn du ihn etwas veränderst, lässt sich das anschaulich mit print() darstellen:

Code: Alles auswählen

for index, weekday in enumerate(WEEKDAYS):
    print(weekday, "->", 1 << index)
Das sind also schon mal die Werte, die du im JavaScript-Code gefunden hast. Es handelt sich dabei um eine klassische Anwendung von Bitverschiebungen.

In der Dezimaldarstellung sind das nur Zahlen, die verdoppelt werden. Um nun zu sehen, wo ein Bit jeweils gesetzt wird, nehmen wir die Binärdarstellung mit rein:

Code: Alles auswählen

for index, weekday in enumerate(WEEKDAYS):
    value = 1 << index
    print(f"{weekday}\t{value}\t{value:>07b}")
Hierbei habe ich eine Darstellung mit 7 Binärstellen gewählt, da diese für die 7 Wochentage stehen und in dem Fall der maximalen Anzahl an genutzten Bits entsprechen.

Und um jetzt zu testen, ob ein Bit gesetzt ist, nimmt man den ``&``-Operator. Falls du mit den Details hierzu nicht vertraut bist, dann gib bitte "binary and" in eine Suchmaschine deiner Wahl ein. Ich spare mir an dieser Stelle die näheren Ausführungen dazu.

Zur Verknüpfung mehrerer Bits nutzt man den ``|``-Operator ("binary or"). Dein Beispiel sprach von Di+Mi+Fr-So. Dies entspricht:

Code: Alles auswählen

1 << 1 | 1 << 2 | 1 << 4 | 1 << 5 | 1 << 6
Beachte, dass der Index immer die "übliche" Zählweise - 1 ist. Und dann schau mal, was raus kommt. Das könnte dir bekannt vorkommen. ;)
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Übrigens, mit den richtigen Importen lässt sich das Erzeugen, Kodieren und Dekodieren auch jeweils als Einzeiler umsetzen:

Code: Alles auswählen

#!/usr/bin/env python3
from enum import IntFlag
from functools import reduce
from operator import or_

Weekday = IntFlag("Weekday", "Mo Di Mi Do Fr Sa So".split())

def long_encode(days):
    result = 0
    for day in days:
        result |= Weekday[day]
    return result

def encode(days):
    return reduce(or_, map(Weekday.__getitem__, days))

def decode(value):
    return [day for day in Weekday if value & day]

def main():
    value = encode(["Di", "Mi", "Fr", "Sa", "So"])
    print(f"{value} -> {value:>07b}")
    print(decode(value))

if __name__ == "__main__":
    main()
Die long_encode()-Funktion demonstriert hierbei bloß die Abläufe in encode() etwas ausführlicher. Die kann man natürlich auch weglassen. :)

Bei der Bitdarstellung sollte einem bewusst sein, dass quasi von rechts nach links gelesen werden muss zum Nachvollziehen der kodierten Wochentage.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Den `split()`-Aufruf kannst Du weg lassen. Die `Enum`-Klassen verhalten sich da wie `collections.namedtuple()` und machen das schon selbst wenn sie eine Zeichenkette übergeben bekommen. 🙂
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wie immer gibt es verschiedene Wege zum Ziel. Diese Variante hat weniger Magie in reduce() und nutzt einen anderen Ansatz zum Auspacken der Bits:

Code: Alles auswählen

#!/usr/bin/env python3
from enum import IntFlag, show_flag_values
from functools import reduce

Weekday = IntFlag("Weekday", "Mo Di Mi Do Fr Sa So")

def pack(day_names):
    return reduce(
        lambda first, second: first | second,
        (Weekday[name] for name in day_names)
    )

def unpack(flag):
    return [Weekday(bit) for bit in show_flag_values(flag)]

def main():
    packed = pack(["Di", "Mi", "Fr", "Sa", "So"])
    print(repr(packed))
    print(unpack(packed))

if __name__ == "__main__":
    main()
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und wer Spaß dran hat, kann sich den Zusammenhang zwischen Bits und angezeigten Wochentagen nochmal damit deutlich machen:

Code: Alles auswählen

#!/usr/bin/env python3
from enum import IntFlag, show_flag_values
from functools import reduce

Weekday = IntFlag("Weekday", "Mo Di Mi Do Fr Sa So")

def names_to_flag(day_names):
    return reduce(
        lambda first, second: first | second,
        (Weekday[name] for name in day_names)
    )

def flag_to_names(flag):
    return [Weekday(bit).name for bit in show_flag_values(flag)]

def main():
    for i in range(30):
        print(flag_to_names(i), "->", bin(i))

if __name__ == "__main__":
    main()
Nun aber genug von mir. Wenn noch Fragen offen sind, kann man die hier gerne äußern...
imonbln
User
Beiträge: 149
Registriert: Freitag 3. Dezember 2021, 17:07

Das Kling für mich nach einem Fall für enum.Flag:

Folgender Code sollte das decodieren hinbekommen.

Code: Alles auswählen

import enum

class Weekdays(enum.IntFlag):
    MO = 0x01
    DI = 0x02
    MI = 0x04
    DO = 0x08
    FR = 0x10
    SA = 0x20
    So = 0x40

flags = Weekdays(56)
for day in Weekdays:
    if day in flags:
        print(day.name)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@imonbln: Öhm, schau doch mal was die ganzen vorhergehenden Beiträge benutzten: `IntFlag`.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten