Station - Funktionen höherer Ordnung

Beispiel: Datensätze sortieren

Im Sportverein werden die Daten der Mitglieder mit einem Programm verwaltet. Für jedes Mitglied liegt ein Datensatz vor, der z.B. Vorname, Nachname, Geburtsdatum etc. enthält.

Daten

Programme zur Verwaltung solcher Daten bieten in der Regel eine Sortierfunktion an.

Daten

Mit Hilfe der Sortierfunktion können die Daten für bestimmte Zwecke umsortiert werden, z.B. nach Name und Vorname oder nach dem Geburtsdatum.

Es gibt eine Reihe von Sortierverfahren zur Realisierung der Sortierfunktion. Wir betrachten im Folgenden das Sortieren durch Einfügen (vgl. ...).

Ein erstes funktionales Programm

Eine funktionale Implementierung dieses Verfahrens könnte so aussehen:.

def einfuegen(e, L):
    if len(L) == 0:
        return [e]
    else:
        if e < L[0]:
            return [e] + L
        else:
            return [L[0]] + einfuegen(e, L[1:])

def sortieren(L):
    if len(L) == 0:
        return L
    else:
        return einfuegen(L[0], sortieren(L[1:]))

Ziel ist es, die Funktion sortieren auf eine Liste mit Personendaten anzuwenden.

personendaten = [
    ('Britta', 'Koch', (23,5,1995)),
    ('Paul', 'Schwarz', (11,11,2003)),
    ('Silke', 'Schmidt', (13,7,1990)),
    ('Jennifer', 'Abel', (15,12,1993)),
    ('Adriana', 'Müller', (21,1,2001)), 
    ('Tobias', 'Klein', (1,3,1997)),
    ('Philipp', 'Bach', (21,4,1997)),
    ('Oliver', 'Schmitt', (14,4,1994)),
    ('Simone', 'Schuster', (20,12,2000)),
    ('Pia', 'Schwarz', (11,11,2003)),
    ('Andreas', 'Beyer', (16,3,1988)),
    ('Alexander', 'Heinrich', (17,3,1999)),
    ('Maximilian', 'Meyer', (21,6,1986))]

Die oben gezeigten Funktionsdefinitionen können noch nicht direkt auf die Liste mit den Personendaten angewandt werden, da die hier vorkommende Vergleichsoperation nicht für Tupel definiert ist. Wir müssen daher die Definitionen an geeigneter Stelle etwas modifizieren. Je nach Sortierkriterium erhalten wir dann leicht veränderte Funktionsdefinitionen:

Alphabetische Sortierung nach dem Nachnamen:

def einfuegen(e, L):
    if len(L) == 0:
        return [e]
    else:
        if e[1] < L[0][1]:
            return [e] + L
        else:
            return [L[0]] + einfuegen(e, L[1:])

def sortieren(L):
    if len(L) == 0:
        return L
    else:
        return einfuegen(L[0], sortieren(L[1:]))

Alphabetische Sortierung nach dem Nach- und Vornamen:

def einfuegen(e, L):
    if len(L) == 0:
        return [e]
    else:
        if e[1] < L[0][1] or (e[1] == L[0][1] and e[0] < L[0][0]):
            return [e] + L
        else:
            return [L[0]] + einfuegen(e, L[1:])

def sortieren(L):
    if len(L) == 0:
        return L
    else:
        return einfuegen(L[0], sortieren(L[1:]))

Aufgabe 1

Vergleiche die verschiedenen Funktionsdefinitionen. Worin unterscheiden sie sich? Teste sie durch Hinzufügen eines Testprogramms.

# Test
personendaten = [
    ('Britta', 'Koch', (23,5,1995)),
    ('Silke', 'Schmidt', (13,7,1990)),
    ('Jennifer', 'Abel', (15,12,1993)),
    ('Adriana', 'Müller', (21,1,2001)), 
    ('Tobias', 'Klein', (1,3,1997)),
    ('Philipp', 'Bach', (21,4,1997)),
    ('Oliver', 'Schmitt', (14,4,1994)),
    ('Simone', 'Schuster', (20,12,2000)),
    ('Pia', 'Schwarz', (11,11,2003)),
    ('Andreas', 'Beyer', (16,3,1988)),
    ('Alexander', 'Heinrich', (17,3,1999)),
    ('Maximilian', 'Meyer', (21,6,1986)), 
    ('Paul', 'Schwarz', (11,11,2003))]

print(sortieren(personendaten))

Aufgabe 2

Die Personendaten sollen nach dem Geburtsdatum (zuerst die/der Jüngste bzw. zuerst die/der Älteste) sortiert werden. Wie müssen die Funktionsdefinitionen abgeändert werden?

Ein verbessertes funktionales Programm

Es fällt auf, dass die Funktionsdefinitionen für die verschiedenen Sortierkriterien bis auf eine Bedingung identisch sind. Nur der Vergleich beim Einfügen muss an das jeweilge Sortierkriterium angepasst werden.

Es ist sicher keine gute Lösung, wenn man für die Funktionsdefinition für jedes Sortierkriterium neu anpassen muss. Geht das nicht auch einfacher? Die Antwort ist ja, wenn man eine Vergleichsrelation als Funktionsparameter zulässt.

Black-Box

Die Black-Box-Modellierungen zeigen Situationen, in denen eine Vergleichsoperation an die Funktion übergeben wird. In der oberen Abbildung wird als Vergleichsoperation der Vergleich der Nachnamen übergeben, in der unteren Abbildung ein Vergleich der Geburtsdaten.

Black-Box

Funktionale Programmierung ermöglicht solche Situationen, in denen einer Funktion Daten übergeben werden können, die selbst eine Funktion darstellen.

Der folgende Quelltext zeigt, wie man die Übergabe einer Funktionen implementiert.

def einfuegen(e, L, vergleich):
    if len(L) == 0:
        return [e]
    else:
        if vergleich(e, L[0]) == True:
            return [e] + L
        else:
            return [L[0]] + einfuegen(e, L[1:], vergleich)

def sortieren(L, vergleich):
    if len(L) == 0:
        return L
    else:
        return einfuegen(L[0], sortieren(L[1:], vergleich), vergleich)

Bei der Verwendung der Funktion muss jetzt die zu benutzende Vergleichsoperation als aktueller Parameter übergeben werden. Im foldenden Testprogramm werden zwei mögliche Verwendungen der funktion aufgezeigt.

# Test

personendaten = [
    ('Jennifer', 'Abel', (15,12,1993)),
    ('Philipp', 'Bach', (21,4,1997)),
    ('Andreas', 'Beyer', (16,3,1988)),
    ('Alexander', 'Heinrich', (17,3,1999)),
    ('Tobias', 'Klein', (1,3,1997)),
    ('Britta', 'Koch', (23,5,1995)),
    ('Maximilian', 'Meyer', (21,6,1986)), 
    ('Adriana', 'Müller', (21,1,2001)), 
    ('Silke', 'Schmidt', (13,7,1990)),
    ('Oliver', 'Schmitt', (14,4,1994)),
    ('Simone', 'Schuster', (20,12,2000)),
    ('Pia', 'Schwarz', (11,11,2003)),
    ('Paul', 'Schwarz', (11,11,2003))]

# Situation 1

def kleinerAlphabetischNachname(person1, person2):
    if person1[1] < person2[1]:
        return True
    else:
        return False

print(sortieren(personendaten, kleinerAlphabetischNachname))

# Situation 2		

def geburtsdatum(person):
    return person[2]

def tag(datum):
    return datum[0]

def monat(datum):
    return datum[1]

def jahr(datum):
    return datum[2]

def kleinerDatum(datum1, datum2):
    if jahr(datum1) < jahr(datum2) or \
       jahr(datum1) == jahr(datum2) and monat(datum1) < monat(datum2) or \
       jahr(datum1) == jahr(datum2) and monat(datum1) == monat(datum2) and tag(datum1) < tag(datum2):
        return True
    else:
        return False

def juenger(person1, person2):
    return kleinerDatum(geburtsdatum(person2), geburtsdatum(person1))

print(sortieren(personendaten, juenger))

Aufgabe 3

Teste die Funktionsdefinitionen. Sortiere die Personendaten auch nach Nach- und Vorname.

Funktionen höherer Ordnung

Eine Funktion höherer Ordnung ist eine Funktion, die Funktionen als Übergabedaten erhält oder eine Funktion als Rückgabedatum zurückliefert.

Ein einfaches Beispiel:

def rechnen(f, a, b):
    return f(a, b)

def add(a, b):
    return a + b

def sub(a, b):
    return a - b

Die Funktion rechnen erwartet als ersten Parameter eine Rechenoperation, die mit Hilfe einer Funktion dargestellt ist. Diese Rechenoperation wird dann auf die weiteren Parameter angewandt. Die folgenden Funktionsaufrufe verdeutlichen das Verhalten der Funktion rechnen.

>>> rechnen(add, 3, 6)
9
>>> rechnen(sub, 5, 2)
3

Aufgabe 4

(a) Kann man die Funktion rechnen auch zur Ausführung von Vergleichsoperationen benutzen? Führe hierzu geeignete Tests durch.

(b) Die Funktion anwenden ist folgendermaßen definiert:

def anwenden(f, a):
    return f(a)

Teste die Funktion anwenden mit verschiedenen konkreten Funktionen.

X

Fehler melden

X

Suche