PDF-Datei

Werbung
hue05
December 14, 2016
HIER und NUR HIER Matrikelnummer und email eintragen; diese Zeile entfernen (s.u)!
1
Abgabehinweise
Beachten Sie unbedingt diese Hinweise, sonst erhalten Sie keine Punkte aus dieser Abgabe! Für
Details siehe z.B. Folien der nullten Zentralübung
1.1
Namen und Matrikelnummern
Tragen Sie Ihre Matrikelnummern und E-Mail-Adressen zeilenweise in die Zelle oberhalb dieser
Zelle ein. Achten Sie dabei streng auf die Formatierung, denn die Auswertung erfolgt automatisch. Entfernen Sie den schon in der Zelle stehenden Text (YOUR ANSWER HERE). Benutzen
Sie keine Leerzeilen. Zwischen Matrikelnummer und E-Mail-Adresse muss genau ein Leerzeichen
stehen; sonst keine Leerzeichen, Tabs, Spiegelstriche, oder ähnliches in einer Zeile. Wir empfehlen
dringend die Benutzung der Uni-Paderborn E-Mail-Adressen!
Format:
MatrikelNummer E-Mail-Adresse
z.B.:
123456 [email protected]
1.2
Abgabe mit Gruppenaccount
Die Abgabe muss mit Ihrem Gruppenaccount erfolgen (gp1_16_. . . ), den Sie in der Präsenzübung
erhalten haben! Abgaben, die über Ihren Einzelaccount erfolgen, werden ignoriert.
1.3
Abgabe: Submit
Es reicht nicht, nur das Übungsblatt zu verändern. Sie müssen unter Assignments auf Submit
clicken (oder entsprechend über die Kommandozeile). Für Details siehe Beschreibung Abgabeprozess.
1.4
Dateinamen
Geben Sie Ihre Lösung in der vom Server erhaltenen Datei hue05.ipynb ab (nicht umbenennen,
keine Kopie erstellen, keine anderen Dateien in das Verzeichnis legen!). Sonst kann eine Bewertung nicht stattfinden.
1
1.5
Struktur des Notebooks
Fügen Sie keine Zellen hinzu und löschen Sie keine Zellen. Ändern Sie nicht den Typ einer Zelle.
Geben Sie Lösungen nur in den Lösungszellen ab. Änderungen in den anderen Zellen werden
nach Abgabe automatisch rückgängig gemacht.
1.6
Code-Zellen
Entfernen Sie die Zeilen mit Inhalt “raise NotImplementedError()” aus den Zellen, in die Sie Ihre
Lösungen schreiben. Ersetzen Sie diese Zeilen durch Ihre eigene Lösungen.
1.7
Nie input
Benutzen Sie niemals die Funktion input(). Das verhindert die automatische Auswertung Ihrer
Abgabe und führt zu 0 Punkten für das gesamte Blatt!
1.8
Kommentare
Kommentieren Sie Code-Abgaben! Insbesondere muss jede Funktion (Klasse, Methode, . . . ) einen
docstring haben! Bei fehlendem docstring werden automatisch Punkte abgezogen!
2
Abgabetermin: 4.12.2016 um 23:59 Uhr
3
Aufgabe 1: King-Kong
3.1
a)
Implementieren Sie eine Funktion king_kong(x), welche für eine gegebene natürliche Zahl x
- ‘King’ zurückgibt, falls x durch 3 teilbar ist oder die Ziffer 3 enthält - ‘Kong’ zurückgibt, falls
x durch 7 teilbar ist oder die Ziffer 7 enthält - ‘KingKong’ zurückgibt, falls x die beiden oberen
Bedingungen erfüllt - x zurückgibt, falls sie keine der oberen drei Bedingungen erfüllt.
In [ ]: def king_kong(x):
### BEGIN SOLUTION
"""Gibt 'King' zurück, falls x durch 3 teilbar ist oder die Ziffer 3 en
falls x durch 7 teilbar ist oder die Ziffer 7 enthält. Gibt 'KingKong'
Falls keine der genannten Bedingungen erfüllt ist, wird x zurückgegeben
Keyword arguments:
x -- (int) die zahl, welche auf oben genannte Bedingungen überprüft wir
Return:
list -- 'King', 'Kong', 'KingKong' oder die Zahl selber
"""
r = x
king_erfuellt = False
if x % 3 == 0 or '3' in str(x):
r = 'King'
2
king_erfuellt = True
if x % 7 == 0 or '7' in str(x):
if king_erfuellt == True:
return 'KingKong'
return 'Kong'
return r
### END SOLUTION
In [ ]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
assert(king_kong(1) == 1)
assert(king_kong(2) == 2)
assert(king_kong(3) == 'King')
assert(king_kong(6) == 'King')
assert(king_kong(7) == 'Kong')
assert(king_kong(17) == 'Kong')
assert(king_kong(28) == 'Kong')
assert(king_kong(21) == 'KingKong')
assert(king_kong(37) == 'KingKong')
In [ ]: # Verändern Sie den Inhalt dieser Zelle nicht.
### HIDESTART
# Teste Ausgaben für durch 3 Teilbare Zahlen:
for i in range(1,30):
if i % 3 == 0 and not (i % 7 == 0 or '7' in str(i)):
assert(king_kong(i) == 'King')
# Teste Ausgaben für durch 7 Teilbare Zahlen:
for i in range(1,30):
if i % 7 == 0 and not (i % 3 == 0 or '3' in str(i)):
assert(king_kong(i) == 'Kong')
# Teste Ausgaben für Zahlen die 3, 7 oder beide Ziffern enthalten:
for i in range(1,30):
if (i % 3 == 0 or '3' in str(i)) and (i % 7 == 0 or '7' in str(i)):
assert(king_kong(i) == 'KingKong')
# Teste Zahlen, für welche kein String zurückgegeben wird:
for i in range(1,30):
if not((i % 3 == 0 or '3' in str(i)) or (i % 7 == 0 or '7' in str(i))):
assert(king_kong(i) == i)
### HIDEEND
3.2
b)
Implementieren Sie eine Funktion king_kong_liste(n), welche für eine gegebene natürliche
Zahl n eine Liste der Zahlen aus {1...n} zurückgibt, für welche die Funktion king_kong aus
Teil a) eine Zahl (also weder 'King' noch 'Kong' noch 'KingKong') zurückgibt.
3
Hinweis: Achten Sie auf Start- und Endindizes. Mit einer List comprehension ist das ganz
leicht.
In [ ]: def king_kong_liste(n):
### BEGIN SOLUTION
"""Gibt für eine gegebene natürliche Zahl n eine Liste der Zahlen aus {
für welche die Funktion king_kong aus Teil a) eine Zahl liefert.
Keyword arguments:
n -- (int) die maximale zahl, für welche king_kong aufgerufen werden so
Return:
list -- eine liste mit zahlen
"""
return [x for x in range(1, n+1) if type(king_kong(x)) == int]
#alternativ:
#
return [x for x in range(1, n+1) if str(king_kong(x)).isnumeric()]
### END SOLUTION
In [ ]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
assert(king_kong_liste(10) == [1, 2, 4, 5, 8, 10])
In [ ]: # Verändern Sie den Inhalt dieser Zelle nicht.
### HIDESTART
assert(king_kong_liste(50) == [1, 2, 4, 5, 8, 10, 11, 16, 19, 20, 22, 25, 2
### HIDEEND
4
Aufgabe 2: Binomialkoeffizienten
4.0.1
a)
Das Pascalsche Dreieck ist eine grafische Darstellung der Binomialkoeffizienten nk , aus der sich
eine einfache Berechnung dieser Koeffizienten ergibt. Dabei kann die Variable n als Zeilenindex und k als Spaltenindex der Einträge des Pascalschen Dreiecks interpretiert werden. Hinweis:
https://de.wikipedia.org/wiki/Pascalsches_Dreieck
Leiten Sie aus dem Pascalschen Dreieck ein rekursives Vorgehen ab, um Binominalkoeffizienten zu berechnen. Schreiben Sie eine Funktion namens pascal, welche zwei ganzzahlige Parameter übergeben bekommt und die entsprechenden Binomialkoeffizienten mit Hilfe des Pascalschen
Dreiecks berechnet und zurückgibt. Implementieren Sie die Funktion pascal mittels Rekursion.
In [ ]: def pascal(row, col):
### BEGIN SOLUTION
"""Compute elements of Pascals triangle
Keyword arguments:
row -- (int) Row nr.
col -- (int) Column nr.
4
Return:
int -- pascal coefficient
"""
if (col == 0 or col == row):
return 1
else:
return pascal(row-1,col-1) + pascal(row-1,col)
### END SOLUTION
In [ ]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
assert(pascal(0,0)==1)
assert(pascal(1,0)==1)
assert(pascal(1,1)==1)
assert(pascal(10,1)==10)
assert(pascal(10,5)==252)
In [ ]: # Verändern Sie den Inhalt dieser Zelle nicht.
### HIDESTART
import math
def nCr(n,k):
return (math.factorial(n))/(math.factorial(k)*math.factorial(n-k))
for n in range(1,20):
for k in range(1,n+1):
assert(pascal(n,k) == nCr(n,k))
### HIDEEND
4.0.2
b)
Schreiben Sie eine Funktion pd_print, die die ersten n Reihen des pascalschen Dreiecks in folgenderm Format ausgibt: 1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
In [ ]: def pd_print(n):
### BEGIN SOLUTION
"""Print elements of Pascal-triangle
Keyword arguments:
n -- (int) nr. of rows
Return:
None
"""
for i in range(0,n):
print(" "*(n-i-1),end="")
for j in range(0,i+1):
print(pascal(i,j),end=" ")
5
print("\n",end="")
### END SOLUTION
In [ ]: # Verändern Sie den Inhalt dieser Zelle nicht.
### HIDESTART
pd_print(1)
print()
pd_print(2)
print()
pd_print(3)
print()
pd_print(4)
print()
pd_print(5)
### HIDEEND
5
Aufgabe 3: Folgen implementieren
5.0.1
a)
Schreiben Sie eine Funktion berechne_folge(n), welche für eine gegebene natürliche Zahl n
eine Liste mit allen Elemenenten der wie folgt definierten Folge ausgibt. Die Elemente der Folge
berechnen sich folgendermaßen:
1.
2.
3.
4.
Beginne mit einer natürlichen Zahl n > 0.
Ist n gerade, so nimm als nächstes n/2.
Ist n ungerade, so nimm als nächstes 3n + 1.
Wiederhole die Vorgehensweise mit der erhaltenen Zahl (als neues n).
Die Folge endet, sobald eine 1 zur Folge hinzugefügt wurde.
In [ ]: def berechne_folge(n):
### BEGIN SOLUTION
"""Berechnet die Elemente der Collatz-Folge für den übergebenen Startpa
Keyword arguments:
n -- (int) Startparameter
Return:
list -- Liste mit den Folgenelementen
"""
L = []
while(True):
L.append(n)
if n == 1:
return L
if n % 2 == 0:
6
n = n//2
else:
n = 3*n+1
### END SOLUTION
In [ ]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
assert(berechne_folge(19) == [19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 1
assert(berechne_folge(15) == [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20,
### HIDESTART
assert(berechne_folge(7) == [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5,
assert(berechne_folge(6) == [6, 3, 10, 5, 16, 8, 4, 2, 1])
assert(berechne_folge(5) == [5, 16, 8, 4, 2, 1])
### HIDEEND
5.0.2
b)
Begründen Sie, warum Sie in Ihrer Implementierung eine while- oder eine for-Schleife benutzt
haben.
• While-Schleife: Anzahl der Elemente der Folge ist nicht von vorneherein klar, daher bietet
sich die While-Schleife an
• for-Schleife: Macht hier keinen Sinn
6
Aufgabe 4
Schreiben Sie eine Funktion matrix_mult(X,Y), welche zwei gegebene Matrizen X = (xij ) ∈
Rl×m und Y = (yij ) ∈ Rm×n , (l, m, n ≥ 1) multipliziert und die Ergebnismatrix Z = (zik ) ∈
Rl×n zurückgibt.
Dabei lässt sich der Eintrag von Z in Zeile i und Spalte k ermitteln durch
Pm
zik =
j=1 xij · bjk . Falls die Dimensionen der übergebenen Matrizen nicht korrekt sind (d.h.
falls die Spaltendimension von X ungleich der Zeilendimension von Y ist), so soll None zurückgegeben werden. Die Darstellung der Eingabematrizen läßt sich an den Tests ablesen. Sie dürfen
annehmen, dass die Dimension der Matrizen immer größer als 0 ist.
Hinweis: Python-Listen werden ab 0 indiziert. Die hier gegebene Definition der Matrix beginnt mit Index ab 1, aber lässt sich natürlich auch analog ab 0 auffassen.
In [ ]: def matrix_mult(X,Y):
### BEGIN SOLUTION
"""Multipliziert die übergebenen Matizen und gibt die Ergebnismatrix zu
unterschiedlichen Dimensionen nicht miteinander multipliziert werden kö
Keyword arguments:
X -- (int) erste Matrix
Y -- (int) zweite Matrix
Return:
list -- None, oder eine Matrix, welche das Ergebnis X*Y enthält
"""
7
# Teste Dimension:
if len(X) != len(Y[0]):
return None
C = [[0 for col in range(len(Y[0]))] for row in range(len(X))]
for i in range(len(X)):
for j in range(len(Y[0])):
for k in range(len(Y)):
C[i][j] += X[i][k]*Y[k][j]
return C
### END SOLUTION
In [ ]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
X = [[12,7,3], [4,5,6], [7,8,9]]
Y = [[5,8,1], [6,7,3], [4,5,9]]
r = matrix_mult(X,Y)
assert(r == [[114, 160, 60], [74, 97, 73], [119, 157, 112]])
# Falsche Dimension:
X = [[12,7,3], [4,5,6], [7,8,9]]
Y = [[5,8], [6,7], [4,5]]
assert(matrix_mult(X,Y) == None)
### HIDESTART
X = [[1,2,3], [4 ,5,3], [1 ,8,6]]
Y = [[5,4,1], [6,2,3], [4,1,3]]
r = matrix_mult(X,Y)
assert(r == [[29, 11, 16], [62, 29, 28], [77, 26, 43]])
### HIDEEND
7
Aufgabe 5
Der Dozent einer Programmiervorlesung nutzt ein tolles neues Tool, um die Lösungen seiner
Studierenden möglichst komfortabel bewerten zu können. Leider erhält er von diesem Tool jedoch
zwei getrennte Listen mit Matrikelnummern und Punkten, wie die folgenden:
matrikel = [12345, 12531, 18034, 17824]
punkte = [19, 13, 0, 20]
Dabei bezieht sich der erste Eintrag in der Liste “Punkte” auf die erste Matrikelnummer, usw.
Praktischer wäre es jedoch, ein dict zu haben, welches Matrikelnummern auf Puntke abbildet,
z. B. so:
matrikel_punkte = {12345: 19, 12531: 13, 18034: 0, 17824: 20}
8
7.0.1
a)
Schreiben Sie eine Funktion namens verknuepfe(l1, l2), an die zwei Listen als Parameter
übergeben werden und die die Verknüpfung dieser beiden Listen als Liste von Tuplen zurückgibt
(so wie matrikel_punkte eine Verknüpfung der Listen matrikel und punkte ist).
Hinweis:
Verwenden
Sie
hierzu
u.
a.
die
Funktion
zip(),
https://docs.python.org/3/library/functions.html#zip
In [2]: def verknuepfe(l1, l2):
### BEGIN SOLUTION
"""Formt zwei Listen in ein dict um, mit den Einträgen der ersten Liste
den Einträgen der zweiten Liste als Werten (gemäß der Reihenfolge der V
Ist eine der beiden Listen kürzer als die andere, werden die verbleiben
anderen Liste ignoriert.
Keyword arguments:
l1 -- (list) Die erste Liste
l2 -- (list) Die zweite Liste
Return:
dict -- Das so erzeugte dict
"""
return dict(list(zip(l1, l2)))
### END SOLUTION
In [3]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
matrikel = [12345, 12531, 18034, 17824]
punkte = [19, 13, 0, 20]
matrikel_punkte = {12345: 19, 12531: 13, 18034: 0, 17824: 20}
assert(matrikel_punkte == verknuepfe(matrikel,punkte))
### HIDESTART
assert({} == verknuepfe([], []))
### HIDEEND
7.0.2
b)
Leider stellt sich nach der Bewertung des dritten Übungsblattes heraus, dass das Bewertungs-Tool
einen merkwürdigen Fehler hat: Befindet sich am Ende der Liste matrikel eine Folge von Matrikelnummern, deren zugehörige Studierende alle null Punkte erreicht haben, so tauchen diese
in der Liste punkte nicht auf. Die liste punkte ist dann also kürzer als matrikel.
Beispiel:
matrikel = [12345, 12531, 18034, 17824, 12635]
punkte = [6, 0, 3]
anstelle von:
punkte = [6, 0, 3, 0, 0]
9
Wie würde Ihre Funktion damit umgehen, dass die Längen der beiden Listen nicht übereinstimmen?
Die betroffenen Matrikelnummern am Ende der Liste würden einfach nicht auftauchen.
7.1
c)
Nach Veröffentlichung der Ergebnisse stellte sich heraus, dass einige Nachkorrekturen nötig
waren. Der Dozent möchte die korrigierten Ergebnisse nun wieder in das Tool geben. Leider
muss man dem Tool dazu wieder zwei Listen von der Form wie matrikel und punkte aus
Teilaufgabe a) übergeben. Ihm liegen die korrigierten Ergebnisse jedoch nur in der Form wie
matrikel_punkte vor.
Schreiben Sie eine Funktion namens entknuepfe(d), welche ein solches dict übergeben
bekommt und ein Paar (also 2-Tupel) der gewünschten Listen zurückgibt.
Verwenden Sie hierzu abermals die Funktion zip().
Hinweis: Sie müssen hier keine Sonderfälle (leeres dict o.ä.) beachten.
In [ ]: def entknuepfe(d):
### BEGIN SOLUTION
"""Erzeugt aus einem dict zwei Listen, die eine mit den Schlüsseln des
den Werten des dicts und zwar so, dass das i-te Element der zweiten Lis
ist, der in der ersten Liste an i-ter Stelle steht.
Keyword arguments:
d -- (dict) Das Eingabe-dict
Return:
(list,list) -- Die beiden von der Funktion erzeugten Listen
"""
entknuepft_als_liste_von_tuples = list(zip(*d.items()))
l1 = list(entknuepft_als_liste_von_tuples[0])
l2 = list(entknuepft_als_liste_von_tuples[1])
return (l1, l2)
### END SOLUTION
In [ ]: # Tests, die Ihre Code bestehen muss
# Verändern Sie den Inhalt dieser Zelle nicht.
matrikel_punkte = {12345: 19, 12531: 13, 18034: 0, 17824: 20}
matrikel_punkte_entknuepft = entknuepfe(matrikel_punkte)
matrikel = matrikel_punkte_entknuepft[0]
punkte = matrikel_punkte_entknuepft[1]
for i in range(len(matrikel)):
assert(punkte[i] == matrikel_punkte[matrikel[i]])
10
8
8.1
Aufgabe 6: Äquivalenz von Code
a)
Gegeben sind die folgenden beiden Codefragmente:
L = [1, 2, 3, 4, 5]
for i in range(len(L)):
L[i] += 1
print(L)
und
L = [1, 2, 3, 4, 5]
L = [x+1 for x in L]
print(L)
Finden Sie Situationen, wo diese beiden Code-Abschnitte nicht den gleichen Effekt haben.
Hinweis: Was ist, wenn es andere Namen für die ursprünliche Liste gibt?
Die folgenden beiden Codefragmente sind nicht äquivalent:
L = [1, 2, 3, 4, 5]
T = L
for i in range(len(L)):
L[i] += 1
print(T) # Gibt [2, 3, 4, 5, 6] aus
L = [1, 2, 3, 4, 5]
T = L
L = [x+1 for x in L]
print(T) # Gibt [1, 2, 3, 4, 5] aus
8.2
b)
Gegeben ist die folgende Funktion schnitt(s1, s2), welche die Schnittmenge zweier Strings
s1 und s2 berechnen soll.
def schnitt(s1,s2):
return [x for x in s1 if x in s2]
Gegeben sind nun zwei beliebige Strings s1 und s2. Überlegen Sie sich, ob die Aufrufe
schnitt(s1,s2) und schnitt(s2,s1) äquivalent sind. Begründen Sie Ihre Antwort.
Die Aufrufe sind nicht äquivalent, wie das folgende Beispiel zeigt.
def schnitt(s1,s2):
return [x for x in s1 if x in s2]
s1 = 'aaabbb'
s2 = 'aabb'
print(schnitt(s1,s2)) # Gibt ['a', 'a', 'a', 'b', 'b', 'b'] aus
print(schnitt(s2,s1)) # Gibt ['a', 'a', 'b', 'b'] aus
11
Im ersten Aufruf wird für jedes a in s1 überprüft, ob sich a in s2 befindet. Da dies der Fall
ist, enthält die resultierende Liste 3 mal 'a'. Im zweiten Aufruf wird lediglich für zwei 'a's
überprüft, ob sich a in s1 befindet, wodurch die Ergebnisliste nur zwei mal 'a' enthält.
9
Aufgabe 7
Neben der Anweisung
if BEDINGUNG:
Block1
else:
Block2
kennt Python einen Ausdruck:
a if BEDINGUNG else b
Sie können Details hier nachlesen: https://docs.python.org/3/reference/expressions.html#conditionalexpressions und https://www.python.org/dev/peps/pep-0308/ (Tutorial z.B. hier:
http://pythoncentral.io/one-line-if-statement-in-python-ternary-conditional-operator/ )
9.1
a)
Setzen Sie Block1, Block2 und a, b zueinander in Bezug - was entspricht was?
Block1 entspricht a, Block2 entspricht b.
9.2
b)
Sind a und b Ausdrücke oder Blöcke?
Es handelt sich hierbei um Ausdrücke (je nachdem, welcher Fall gilt, wird das Ergebnis des
Gesamt-Ausdrucks einer dieser Ausdrücke).
10
Aufgabe 8
Angenommen, Sie haben zwei geschachtelte Schleifen. In der inneren Schleife führen Sie ein
continue durch. Geben Sie ein Code-Beispiel an, aus dem ersichtlich wird, ob nur die innere
oder auch die äußere Schleife beeinflusst wird.
In [ ]: for i in range(2):
print('i:', i)
for j in range(100):
if j >= 3:
continue
print('j:', j)
print('i after:', i)
12
In [ ]: # Verändern Sie den Inhalt dieser Zelle nicht.
### HIDESTART
assert(king_kong.__doc__ != None)
assert(king_kong_liste.__doc__ != None)
assert(pascal.__doc__ != None)
assert(pd_print.__doc__ != None)
assert(berechne_folge.__doc__ != None)
assert(matrix_mult.__doc__ != None)
assert(verknuepfe.__doc__ != None)
# assert(verknuepfe_besser.__doc__ != None)
assert(entknuepfe.__doc__ != None)
### HIDEEND
13
Herunterladen