Besprechung der Klausur python-101, Mo 2024-07-08#

Besprechung und Loesungshinweise 2024-11-08

WICHTIG: Dieses Jupyter Notebook ist in der Klausur python-101 lediglich ein erlaubtes Hilfsmittel unter vielen anderen Hilfsmitteln, ähnlich einem anonym benutzbaren Taschenrechner. Zwar wird dieses Notebook technikbedingt zeitweise gespeichert, aber es gibt keine Verbindung zu Ihrer Person. Insbesondere können ihre Eingaben im Notebook vom Dozenten nicht eingesehen und auch nicht bewertet werden.

Also: Übertragen Sie alle Ergebnisse aus dem Notebook auf Papier. Es wird ausschließlich die Papier-Version der Klausur bewertet.

Dauer der Klausur:

  • 60 Minuten

  • plus 10 Minuten Karenzzeit zum Übertragen der Ergebnisse auf Papier.

Name, Vorname, MatNr etc.:

  • in der Papierklausur: Nur auf dem letzten Blatt “Persönliche Angaben” angeben, damit ich anonym korrigieren kann.

  • in der elektronischen Version NICHT angebeben, sondern anonym benutzen – ähnlich wie einen Taschenrechner.

Operatoren#

gegeben seien die folgenden Variablen:

l = [ 1, 2, 3 ]
s = { 7, 9, 8 }
hallo = "Hallo"
welt = "Welt!"
vokale = { 'a', 'e', 'i', 'o', 'u'  }

Verwenden Sie obige Variablen sowie eine geeignete Programmierung, um die Tests auf Gleichheit Wahr zu machen. Beispiel:

"HalloHallo" == ...
# Lösung:
"HalloHallo" == 2 * hallo
True

Aufgabe:

"Hlo" == hallo[::2]  # gut so
"Hlo" == hallo[0] + hallo[2] + hallo[4]  # nicht gut so, kein Punkt, weil nicht "geeignete Programmierung"
True

Aufgabe:

'!lW' == welt[::-2] 
True

Aufgabe: Die Menge aller Vokale in einem String wie z.B. hallo:

{ 'a', 'o' } == set( hallo ).intersection(vokale)
True

Aufgabe:

'123' == "".join( [ str(x) for x in l ] )
True

Aufgabe:

[7, 8, 9] == sorted(s)
True

Dictionaries: gemeinsame key-value-Paare?#

gegeben: 2 Dicts, z.B.

d1 = { 0: "null", 1: "eins", 2: "zwei",            9: "neun"}
d2 = { 0: "null",            2: "zwei", 3: "drei", 9: "девять"}

gesucht:

  • ein Dict d12, das alle key-value Paare enthält, bei denen der Schlüssel und der Wert übereinstimmen, hier: d12 == {0: 'null', 2: 'zwei'}

d12 = ...

# Ansatz: Grundstruktur "Durchgehen durch ein Dict"

d12 = {} # ein Dict

for k,v in d1.items():
    ...
    # wir haben k und v aus d1: sind die auch so in d2 enthalten?
    # wenn ja: zum Ergenbnis d12 hinzufügen
d12 == {0: 'null', 2: 'zwei'}
False

Schnittmenge von Listen#

gegeben: zwei Listen, z.B.

l1 = [ 1, 2, 3, 2, 1 ]
l2 = [ 2, 3, 4, 5 ]

Aufgabe: Definieren Sie eine Funktion listen_schnittmenge(a, b), die eine Menge aller Elemente zurückgibt, die in Liste a und Liste b enthalten sind. Mehrfach auftretende Elemente werden nur einmal aufgeführt, die Reihenfolge spielt keine Rolle.

def listen_schnittmenge(a, b):
    # Ergebnis: Schnittmenge von a und b als Menge

    menge = ...
    return menge
sorted(listen_schnittmenge( l1, l2 )) == [2, 3 ]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[13], line 1
----> 1 sorted(listen_schnittmenge( l1, l2 )) == [2, 3 ]

TypeError: 'ellipsis' object is not iterable

Dieselpreise in Landshut#

gegeben:

  • Eine Liste von Diesel-Preisen zu einem bestimmten Zeitpunkt, z.B.

diesel = {
  ('LA', 'Niedermayerstr. 54') : 1.61,
  ('LA', 'Oberndorfer Str. 23 a'): 1.62,
  ('LA', 'Podewilsstr. 12'): 1.57,
  ('Altdorf', 'Am Aicher Feld 1'): 1.63,
  ('Altdorf', 'Äußere Parkstr. 21'): 1.57 }

gesucht:

  • minimaler Diesel-Preis an diesem Tag?

diesel_min = min( diesel.values() )
diesel_min == 1.57
True

gesucht:

  • Welche Städte sind in diesel enthalten?

# Grundstruktur

ergebnis = []

for x in diesel.keys():
    #print(x[0])
    ergebnis.append( x[0] )

set( ergebnis )
{'Altdorf', 'LA'}
staedte = { x[0] for x in diesel.keys() } # volle Punktzahl
staedte == {'Altdorf', 'LA'}
True

Zusatzfrage: Die nächste Zelle wirft einen Fehler TypeError: unhashable type: 'list':

  • Woher kommt der Fehler, was “bedeutet” er?

  • Reparieren Sie den Fehler!

diesel_DEFUNCT = { ['LA', 'Niedermayerstr. 54'] : 1.61 }
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[58], line 1
----> 1 diesel_DEFUNCT = { ['LA', 'Niedermayerstr. 54'] : 1.61 }

TypeError: unhashable type: 'list'
diesel_repariert = { ('LA', 'Niedermayerstr. 54') : 1.61 }
diesel_repariert
{('LA', 'Niedermayerstr. 54'): 1.61}

Datenstruktur vereinfachen#

Gegeben wieder obige Datenstruktur zu den Dieselpreisen:

diesel = {
  ('LA', 'Niedermayerstr. 54') : 1.61,
  ('LA', 'Oberndorfer Str. 23 a'): 1.62,
  ('LA', 'Podewilsstr. 12'): 1.57,
  ('Altdorf', 'Am Aicher Feld 1'): 1.63,
  ('Altdorf', 'Äußere Parkstr. 21'): 1.57 }

Diese Datenstruktur ist nicht optimal. Schöner wäre ein Dict Stadt -> Straße -> Preis (z.B. {'LA': {'Niedermayerstr. 54': 1.61, ... }, ...}.

Aufgabe: Erstellen Sie aus diesel eine solche Datenstruktur diesel2.

diesel2 = {}
diesel2 == {'LA': {'Niedermayerstr. 54': 1.61,
  'Oberndorfer Str. 23 a': 1.62,
  'Podewilsstr. 12': 1.57},
 'Altdorf': {'Am Aicher Feld 1': 1.63, 'Äußere Parkstr. 21': 1.57}}
True

Zweier-Kombinationen#

Gegeben:

  • eine Zahl n, z.B. n = 3

Gesucht:

  • eine Liste aller Mengen mit zwei Elementen, die sich aus je zwei Zahlen zwischen 1 und n erzeugen lassen.

Lösen Sie idealerweise mit einer List-Comprehension.

n = 3
zweier = ...
... # 
zweier == [{1, 2}, {1, 3}, {2, 3}]
True

Dict durchsuchen#

gegeben:

  • ein Dict von Menschen mit ihren Hobbies

  • eine Menge von typischen Abend-Hobbies

Lösen Sie bevorzugt mit Mengen und Comprehensions.

hobby_dict = {
    'Alice': ['Lesen', 'Reisen', 'Tanzen'], 
    'Bob': ['Fotografie'],
    'Charlie': ['Lesen', 'Tanzen'] }
Abend = {'Lesen', 'Tanzen'}

Aufgabe: Welche Personen gibt es?

personen = ...
... # 
personen == {'Alice', 'Bob', 'Charlie'}
True

Aufgabe: Welche Hobbys gibt es insgesamt?

hobbys = ...
... # 
hobbys == {'Fotografie', 'Lesen', 'Reisen', 'Tanzen'}
True

Aufgabe: Welche Personen haben ein Abend-Hobby?

ahp = ... # Abend-Hobby-Personen
... # 
ahp == {'Alice', 'Charlie'}
True

Aufgabe: Welche Personen haben KEIN Abend-Hobby?

kahp = ... # keine Abend-Hobby-Personen
... # 
kahp == {'Bob'}
True

eine Funktion definieren#

Ein n-Gramm ist das Ergebnis der Zerlegung eines Textes in Fragmente, hier: ein String aus jeweils n (typischerweise n = 3) aufeinanderfolgenden Buchstaben eines Wortes.

(Ein Wort sei ein String, der nur aus Buchstaben besteht, z.b. wort = 'Hallo'.)

Beispiel, spezielle Lösung: Eine Liste z.B. der 3-Gramme von z.B. 'Hallo' kann man z.B. wie folgt erstellen:

[ "Hallo"[i:i+3] for i in range( len("Hallo")-2 ) ] 
['Hal', 'all', 'llo']

gesucht:

  • eine allgemeine Funktion ngramm(wort, n), die die obige Beispiellösung verallgemeinert, also für beliebige n eine Liste aller n-Gramme eines Wortes zurückgibt.

Implementierungsdetails:

  • n ist optional; falls n nicht angegeben ist, nehmen wir defaultmäßig n = 3 an.

  • Falls n größer als die Wortlänge, geben wir None zurück

def ngramm(wort,n=3):
    if n > len(wort):
        return None
    else:
        ergebnis = [ wort[i:i+n] for i in range( len(wort)-n+1 ) ] 
        return ergebnis    
ngramm("Hallo") == ['Hal', 'all', 'llo']
True
ngramm("Hallo", 4) == ['Hall', 'allo']
True
ngramm("Hallo", 6) == None
True

Datum als String#

gegeben:

  • ein Dict, das die Zahlen 1-12 auf Monatsnamen mappt

  • Eine Geburtstagsverzeichnis

Monatsnamen = { 1: "Januar", 2: "Februar", 3: "März", 
               4: "April", 5: "Mai", 6: "Juni", 
               7: "Juli", 8: "August", 9: "September",
               10: "Oktober", 11: "November", 12: "Dezember" }

Geburtstage = {
 'Knuth': {'J': 1938, 'M': 1, 'T': 10}, # 10. Januar 1938
 'Duck': {'J': 1934, 'M': 6, 'T': 9},   # 9. Juni 1934
 'Trump': {'J': 1946, 'M': 6, 'T': 14}} # 14. Juni 1946

Aufgabe, Teil 1#

gesucht:

  • eine Funktion datumstring(*, T, M, J), die ein Datum aus unserem Geburtstagsverzeichnis als String zurückgibt, wie es in der BRD üblich ist

def datumstring(*, T, M, J):
    ... # 

Testen Sie Ihre Funktion, indem Sie mit Ihrer Funktion z.B. für Donald Duck den Datumstring berechnen:

# ds_duck: Datum String von Donald Duck
... # 
ds_duck == '9. Juni 1934'
True

Aufgabe, Teil 2#

Fügen Sie zu allen Einträgen im Geburtstagsverzeichnis G2 den jeweiligen Datumstring hinzu!

G2 = {
 'Knuth': {'J': 1938, 'M': 1, 'T': 10}, # 10. Januar 1938
 'Duck': {'J': 1934, 'M': 6, 'T': 9},   # 9. Juni 1934
 'Trump': {'J': 1946, 'M': 6, 'T': 14}} # 14. Juni 1946 }

for k,v in G2.items():
    ... # 
G2 == {'Knuth': {'J': 1938, 'M': 1, 'T': 10, 'DS': '10. Januar 1938'},
 'Duck': {'J': 1934, 'M': 6, 'T': 9, 'DS': '9. Juni 1934'},
 'Trump': {'J': 1946, 'M': 6, 'T': 14, 'DS': '14. Juni 1946'}}
True

Textdatei einlesen und auswerten#

Im selben Ordner wie dieses Jupyter Notebook liegt die die Datei ottos_mops.txt.

Die Datei enthält ein Gedicht von Ernst Jandl:

gedicht = """ottos mops trotzt
otto: fort mops fort
ottos mops hopst fort
otto: soso

otto holt koks
otto holt obst
otto horcht
otto: mops mops
otto hofft

ottos mops klopft
otto: komm mops komm
ottos mops kommt
ottos mops kotzt
otto: ogottogott
"""

Aufgabe: lesen Sie die Datei in den String gedicht_aus_datei ein!

gedicht_aus_datei = None

with open("ottos_mops.txt", "r") as otto_file:
    ... # 
# print(gedicht_aus_datei)
gedicht_aus_datei == gedicht
True

Aufgabe: Wie oft kommt das Wort mops in gedicht vor?

anzahl_mops = ...
... # 
anzahl_mops == 9
True

Aufgabe: Wie viele Textzeilen enthält gedicht?

anzahl_textzeilen = ...
... # 
anzahl_textzeilen == 14
True

Aufgabe: Wie oft kommt jeder Vokal vor?

vokale = { 'a', 'e', 'i', 'o', 'u' }
zaehlung_vokale = { x: 0 for x in vokale}
zaehlung_vokale
{'e': 0, 'a': 0, 'o': 0, 'u': 0, 'i': 0}
... # 
    ... # 
        ... # 
zaehlung_vokale == {'a': 0, 'o': 59, 'i': 0, 'e': 0, 'u': 0}
True

Familienname:

Vorname:

Matrikelnummer:

Studiengang:

freiwillige Angaben, nicht bewertungsrelevant:

Drittversuch?

Punkte auf Codewars?