Naloge - funkcijsko programiranje

V teh vajah najdete tudi nekaj nalog, ki smo jih reševali tudi že v prejšnjih nalogah. Sedaj bomo te naloge reševali na funkcijski način. Ko rešite, lahko primerjate rešitev z vašo proceduralno rešitvijo.

V teh nalogah je raba vsakršnih zank strogo prepovedana. Vse naloge rešujemo s funkcijami map, filter, in reduce.

Kvadriraj

Napišite funkcijo kvadriraj(xs), ki kvadrira vsako število v seznamu xs.

>>> kvadriraj([1, 2, 3, 4, 5])
[1, 4, 9, 16, 25]

Rešitev

def kvadriraj(xs):
    return list(map(lambda x: x ** 2, xs))

Samo pozitivna

Napišite funkcijo samo_pozitivna(xs), ki vrne seznam vseh pozitivnih števil.

>>> samo_pozitivna([-1, 5, -2, -1, 7, 0])
[5, 7]

Rešitev

def samo_pozitivna(xs):
    return list(filter(lambda x: x > 0, xs))

Vsota števil

Napišite funkcijo vsota(xs), ki izračuna vsoto števil v seznamu.

>>> vsota([-1, 5, -2, -1, 7, 0])
8

Rešitev

def vsota(xs):
    return reduce(lambda acc, x: acc + x, xs)

Produkt sodih števil

Napišite funkcijo produkt_sodih(xs), ki izračuna produkt vseh sodih števil v seznamu xs. Funkcija naj za prazen seznam vrne 1.

>>> produkt_sodih([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
3840

Rešitev

def produkt_sodih(xs):
    return reduce(lambda acc, x: acc * x, filter(lambda x: x % 2 == 0, xs))

Največji

Napišite funkcijo najvecji(xs), ki vrne največje število v seznamu xs. V tej nalogi je prepovedano uporabljati funkcijo max in njene ekvivalente. Funkcija za prazen seznam ni definirana.

>>> najvecji([5, 1, -6, 6, -7, 2])
5

Rešitev

def najvecji(xs):
    return reduce(lambda acc, x: x if x > acc else acc, xs)

Največji absolutist

Napišite funkcijo naj_abs(xs), ki vrne največje število po absolutni vrednost v seznamu xs. V tej nalogi je prepovedano uporabljati funkcijo max in njene ekvivalente.

>>> naj_abs([5, 1, -6, 6, -7, 2])
-7

Rešitev

def naj_abs(xs):
    return reduce(lambda acc, x: x if abs(x) > abs(acc) else acc, xs)

Najdaljša beseda

Napiši funkcijo najdaljsa(s), ki vrne najdaljšo besedo v nizu s. Pomagajte si z metodo split().

>>> najdaljsa('an ban pet podgan')
'podgan'

Rešitev

def najdaljsa(s):
    return reduce(lambda acc, s: s if len(s) > len(acc) else acc, s.split(" "))

Nalogo lahko rešimo tudi na drug način

def najdaljsa(s):
    besede = s.split(" ")
    kandidati = zip(besede, map(len, besede))
    najdaljsa_beseda = reduce(lambda acc, x: x if x[1] > acc[1] else acc, kandidati)
    return najdaljsa_beseda[0]

Sumljive besede

Napiši funkcijo sumljive(s), ki vrne seznam vseh sumljivih besed v danem nizu. Beseda je sumljiva, če vsebuje tako črko u kot črko a.

>>> sumljive('Muha pa je rekla: "Tale juha se je pa res prilegla, najlepša huala," in odletela.')
['Muha', 'juha', 'huala,"']

Rešitev

def sumljive(s):
    return list(filter(lambda w: "u" in w and "a" in w, s.split(" ")))

Največji podseznam

Napiši funkcijo, ki vrne podseznam z največjo vsoto elementov. Za gornji seznam mora funkcija vrniti [8, 2], saj je to podseznam z največjo vsoto, namreč 10. Funkcija za prazen seznam ni definirana.

>>> najvecji_podseznam([[1, 1, 1], [1, 1]])
[1, 1, 1]
>>> najvecji_podseznam([[2, 4, 1], [3, 1], [], [8, 2], [1, 1, 1, 1]])
[8, 2]

Rešitev

def najvecji_podseznam(xs):
    return reduce(lambda acc, x: x if sum(x) > sum(acc) else acc, xs)

Cezarjeva šifra

Napišite program, ki podan niz zašifrira z uporabo cezarjeve šifre. Preden se lotite naloge, se je morda vredno pozanimati kaj počneta funkciji ord in chr. Predpostavite lahko, da niz s vsebuje le male črke angleške besede in presledke.

>>> cezar("the quick brown fox jumps over the lazy dog")
"wkh txlfn eurzq ira mxpsv ryhu wkh odcb grj"

Rešitev

def cezar(s):
    def _replace(l):
        return l if l == " " else chr(((ord(l) - ord("a") + 3) % 26) + ord("a"))
    return "".join(map(_replace, s))

Palindrom

Napišite funkcijo palindrom(s), ki preveri, ali je niz s palindrom. Pomagajte si s funkcijo reversed. V rešitvi lahko uporabite funkcijo all, lahko pa za vajo implementirate tudi svojo verzijo.

>>> palindrom("pericarezeracirep")
True
>>> palindrom("perica")
False

Rešitev

def palindrom(s):
    return _all(map(lambda x: x[0] == x[1], zip(s, reversed(s))))

def _all(xs):
    return reduce(lambda acc, x: acc and x, xs)

Lokalni maksimum

Napišite funkcijo lokalni_maksimum(xs), ki poišče vse lokalne maksimume v seznamu števil. Število je lokalni maksimum takrat, ko je večje od številke na levi in številke na desni strani.

>>> lokalni_maksimum([2, 9, 5, 6, 1])
[9, 6]
>>> lokalni_maksimum([2, 3, 4, 1, 5])
[4]
>>> lokalni_maksimum([1, 2, 3, 4, 5]) 
[]

Rešitev

def lokalni_maksimum(xs):
    kandidati = zip(xs, xs[1:], xs[2:])
    maksimumi_terke = filter(lambda x: x[1] > x[0] and x[1] > x[2], kandidati)
    return list(map(lambda x: x[1], maksimumi_terke))

Hladilnik

Napišite funkcijo stanje_hladilnika(zacetno_stanje, dogodki), ki sprejme začetno stanje hladilnika in seznam dogodkov, ki vplivajo na stanje v hladilniku. Funkcija naj vrne končno stanje hladilnika.

Stanje hladilnika beležimo s slovarjem, kjer je ključ slovarja posamezen izdelek, vrednost pa količina tega izdelka. Dogodki so lahko dveh tipov: "porabi", ki zniža količino izdelka v hladilniku, ter "kupi", ki poviša količino izdelka v hladilniku.

Ker je cilj naloge spoznavanje funkcijskih principov programiranja, naj bo to čarobni hladilnik, ki ima lahko tudi negativne količine posameznih izdelkov (npr. hladilnik ima lahko tudi -4 litre mleka).

>>> hladilnik = {"kruh": 5, "mleko": 3}
>>> dogodki = [
    ("porabi", "mleko", 0.2),
    ("kupi", "mleko", 3),
    ("kupi", "kruh", 2),
    ("kupi", "sir", 2),
    ("porabi", "kruh", 0.2),
    ("porabi", "sir", 0.3),
]
>>> stanje_hladilnika(hladilnik, dogodki)
{'kruh': 6.8, 'mleko': 5.8, 'sir': 1.7}

Rešitev

def obdelaj_dogodek(stanje, dogodek):
    vrsta_dogodka, izdelek, kolicina = dogodek
    if vrsta_dogodka == "kupi":
        stanje[izdelek] = stanje.get(izdelek, 0) + kolicina
    elif vrsta_dogodka == "porabi":
        stanje[izdelek] = stanje.get(izdelek, 0) - kolicina
    return stanje

def stanje_hladilnika(zacetno_stanje, dogodki):
    return reduce(obdelaj_dogodek, dogodki, zacetno_stanje)

Binarna števila

Napišite funkcijo v_desetisko, ki pretvori binarno število podano s seznamom v desetiško.

>>> v_desetisko([0, 0, 1, 0, 1])
5

Rešitev

def v_desetisko(xs):
    return reduce(lambda acc, x: acc + 2 ** x[0] * x[1], enumerate(reversed(xs)), 0)

Zadnja sprememba: ponedeljek, 29. november 2021, 10.54