Geschrieben von as_string am 02.11.2017 um 22:45:
Hallo!
Eins vorne weg: Ich hab noch nie ein Python-Programm geschrieben!
Allerdings habe ich etwas gegooglet und das hier probiert:
code: |
1:
2:
3:
4:
5:
6:
7:
|
hobbys = ["Schwimmen", "Brettspiele", "Angeln", "Kochen", "Laufen", "Fußball spielen", "Klavier spielen", "Nähen"]
number = int(input('-->'))
for idx, hobby in enumerate(hobbys):
if((1 << idx) & number):
print(hobby)
|
|
Die for-Schleife habe ich mit dem enumerate gemacht, um immer auch den Index im Array mit zu bekommen. So ist in idx zuerst eine 0 wenn in hobby "Schwimmen" ist, eine 1, wenn in hobby "Brettspiele" steht und eine 2 bei "Angeln" usw.
Die if-Bedingung ist dabei interessant: 1 << idx nutzt den bit-shift Operator "<<". Der nimmt die Zahl, die links steht (also die 1) und verschiebt alle Bit um die Anzahl der Stellen, die in idx aktuell steht.
Also Beispiel: Die 1 ist ja in Binärdarstellung:
00000001
wenn idx gerade 3 wäre, würde die 1 verschoben, so dass man das hier hat:
00001000
Das wieder zurück ins Dezimalsystem gewandelt ergibt einfach eine 8
Das bedeutet: Man bekommt auf diese Weise gerade die Zahlen, die den einzelnen Hobbys zugeordnet sind.
Als nächstes habe ich den Bitwise-Und-Operator verwendet, das ist einfach das Kaufmanns-und. Das macht für jedes einzelne Bit der Zahl links und rechts eine und-Verknüpfung und setzt nur dann das Bit im Ergebnis, wenn beide Bit der Eingabezahlen auch gesetzt sind.
Angenommen die Eingabezahl war die 11. Das würde für Schwimmen, Brettspiele und Kochen stehen.
Im ersten Schleifendurchlauf ist idx 0. Dann würde der Ausdruck 1 << idx die 1 gar nicht verschieben (halt um 0 Stellen...), also ist das Ergebnis immer noch eine 1.
Als nächstes käme diese Und-Verknüpfung. Da die eben ausgerechnete Zahl (also die 1) nur ein Bit gesetzt hat, nämlich das erste (oder letzte, je nachdem von wo aus Du zählst, auf jeden Fall das niederwertigste), werden automatisch alle anderen Bit 0. Egal was in der Zahl auf der rechten Seite drin steht, wenn links schon eine 0 ist, ergibt die Und-Verknüpfung auch eine 0. Nur an der Stelle, bei der links die Eins steht, könnte es vielleicht ein anderes Ergebnis geben, wenn zufällig rechts auch eine 1 an dieser Stelle wäre.
Man nennt so etwas auch eine "Maske". Nur die Bit, die in der Maske gesetzt sind, können auch im Ergebnis durch kommen. Man nimmt also die eingegebene Zahl und hält eine Maske drüber, die in unserem Fall nur ein Loch hat (nämlich bei der 1). Dort scheint das Bit von der Eingabezahl durch, alle andere Stellen werden 0.
Diese Maske verschieben wir durch die <<idx-Operation bei jedem Schleifendurchlauf eine Stelle weiter. Auf diese Art filtern wir jedes einzelne Bit von number nach und nach aus, bei jedem Schleifendurchlauf ein anderes.
Bei dem Python-if scheint es so zu sein, wie in vielen anderen C-artigen Programmiersprachen auch: Wenn eine Zahl in der Bedingung steht, dann wird nur die 0 als false interpretiert, alle anderen Zahlen werden true. Deshalb genügt es auch, die Bedingung so zu schreiben, wie ich das getan habe: Wenn die Maske gerade über einer 0 steht, wird das Ergebnis auch 0 --> false, wenn es über einer 1 stand, dann wird es irgendeine andere Zahl sein --> true.
Das mit Maske und Bit-Operationen ist in diesem Zusammenhang ein sehr wichtiges und häufig verwendetes Konzept (eher in Hardware-naher Programmierung, aber manchmal auch sonst wo). Es mag zuerst recht befremdlich erscheinen, aber für Computer ist das die natürlichste Art, etwas zu rechnen. Wenn man damit geschickt arbeitet, kann man manche Dinge unglaublich schnell mit dem Computer machen. Z. B. ist das im Netzwerkbereich mit den ganzen Subnetting ein Thema. Aber auch in sehr vielen anderen Gebieten. Auch die Verwendung wie hier von der Art Menge (oder englisch Set) ist eine gebräuchliche Anwendung.
Gruß
Marco
Geschrieben von as_string am 02.11.2017 um 23:35:
Also ich mag es in solchen Fällen eigentlich, wenn man gleich mitzählt, wie viele Hobbys gefunden wurden. Das ist besser, als nur True/False und hat aber auch keine Nachteile, weil keine Hobbys gefunden wird ja dann 0 und 0 ist False, sobald eines gefunden wurde oder auch mehrere, dann ist die Variable True. Sie hat also mehr Information (nämlich auch die tatsächliche Anzahl) aber ohne Umstände auch die True/False Information.
Dann würde man vor der Schleife
schreiben und ganz am Ende:
code: |
1:
2:
|
if not found:
print("Keine Hobbys gefunden") |
|
Und zum print im inneren if-Block innerhalb der for-Schleife dann noch found jedes Mal um eins hochzählen, mit "found += 1" z. B.
Gruß
Marco