Compare commits

...

10 Commits

Author SHA1 Message Date
1121c6a171 added prime generator 2024-01-30 17:18:24 +01:00
9ea341183d renamed test.py 2024-01-30 16:31:20 +01:00
801b641fb2 added README.md to list comprehensions 2024-01-30 16:14:14 +01:00
f3e49c96cd added exercises for list comprehensions 2024-01-30 15:50:40 +01:00
f89435117a added :D 2024-01-30 14:34:14 +01:00
56c0d4bec3 added string exercise 2024-01-30 11:21:28 +01:00
407389a5cb added string exercise 2024-01-30 11:15:45 +01:00
da878ec3e6 added sorting exercise 2024-01-30 05:01:05 +01:00
8ed82e01aa fixed formatting 2024-01-30 02:17:48 +01:00
23f4c7be52 fixed formatting 2024-01-30 02:15:09 +01:00
20 changed files with 634 additions and 12 deletions

View File

@@ -1,33 +1,33 @@
# Übungsaufgaben zur EidP (WS2023) Klausur # Übungsaufgaben zur EidP (WS2023) Klausur
Alle Aufgaben hier behandeln Konzepte aus der Vorlesung **Einführung in die Programmierung** von der Albert-Ludwig-Universität Freiburg. Hierbei handelt es sich um selbsterstellte Aufgaben der EidP-Tutoren [**Nils Pukropp**](mailto:nils@narl.io) und [**Daniel Mironow**](mailto:mail@danielmironov.dev) die bei der Vorbereitung auf die Klausur helfen sollen. Alle Aufgaben hier behandeln Konzepte aus der Vorlesung **Einführung in die Programmierung** von der Albert-Ludwig-Universität Freiburg. Hierbei handelt es sich um selbsterstellte Aufgaben der EidP-Tutoren [**Nils Pukropp**](mailto:nils@narl.io) und [**Daniel Mironow**](mailto:mail@danielmironov.dev) die bei der Vorbereitung auf die Klausur helfen sollen. :D
## Reihenfolge der Themen ## Reihenfolge der Themen
Es gibt keine direkte Reihenfolge, lediglich Themen die sich teilweise überschneiden. Dennoch gibt es eine Reihenfolge nach Wichtigkeit der Themen: Es gibt keine direkte Reihenfolge, lediglich Themen die sich teilweise überschneiden. Dennoch gibt es eine Reihenfolge nach Wichtigkeit der Themen:
- [Grundkonzept Schleifen (`for`, `while`, ...)](./loops) - [Grundkonzept Schleifen (`for`, `while`, ...)](src/branch/main/loops)
- allgemeine Knobelaufgaben rund um Schleifen - allgemeine Knobelaufgaben rund um Schleifen
- Einfach mit ein paar schwierigeren Aufgaben zum Nachdenken - Einfach mit ein paar schwierigeren Aufgaben zum Nachdenken
- [Zeichenketten (Strings `str`)](./strings) - [Zeichenketten (Strings `str`)](src/branch/main/strings)
- allgemeine Knobelaufgaben rund um `str` - allgemeine Knobelaufgaben rund um `str`
- Einfach mit ein paar schwierigeren Aufgaben zum Nachdenken - Einfach mit ein paar schwierigeren Aufgaben zum Nachdenken
- [Dataclasses (OOP `@dataclass`)](./dataclasses) - [Dataclasses (OOP `@dataclass`)](src/branch/main/dataclasses)
- Objekt orientierte Programmierung mit `@dataclass` - Objekt orientierte Programmierung mit `@dataclass`
- Einfach (Auswendig lernen) - Einfach (Auswendig lernen)
- [Pattern Matching (`match`)](./pattern_matching) - [Pattern Matching (`match`)](src/branch/main/pattern_matching)
- Intensive Übungen zu `match` - Intensive Übungen zu `match`
- Mittel (Auswendig lernen, aber erfordert grundlegende Konzepte) - Mittel (Auswendig lernen, aber erfordert grundlegende Konzepte)
- [Typvariabeln (Generics `[T]`)](./generics) - [Typvariabeln (Generics `[T]`)](src/branch/main/generics)
- Platzhalter Variabeln um generische Typannotation umzusetzen - Platzhalter Variabeln um generische Typannotation umzusetzen
- Mittel (Auswendig lernen, aber erfordert grundlegende Konzepte) - Mittel (Auswendig lernen, aber erfordert grundlegende Konzepte)
- [Rekursion (Tree)](./recursion) - [Rekursion (Tree)](src/branch/main/recursion)
- Sich selbst aufrufende Funktionen - Sich selbst aufrufende Funktionen
- Schwer, da das Konzept etwas verwirrend ist, aber gut für schnelle Punkte in der Klausur! - Schwer, da das Konzept etwas verwirrend ist, aber gut für schnelle Punkte in der Klausur!
- [Generator](./generator) - [Generator](src/branch/main/generator)
- Erzeugen von Iteratoren auf die seltsame Python Art und Weise! - Erzeugen von Iteratoren auf die seltsame Python Art und Weise!
- Mittel, da das Konzept etwas seltsam ist. Muss man einfach ein paar mal machen! - Mittel, da das Konzept etwas seltsam ist. Muss man einfach ein paar mal machen!
- [Funktionale Programmierung](./functional_programming) - [Funktionale Programmierung](src/branch/main/functional_programming)
- Programmieren-Paradigma bei dem der Programmfluss durch Funktionen bestimmt wird! - Programmieren-Paradigma bei dem der Programmfluss durch Funktionen bestimmt wird!
- Schwer, da das Konzept etwas schwer zu verstehen ist und viele Grundlagen vorraussetzt - Schwer, da das Konzept etwas schwer zu verstehen ist und viele Grundlagen vorraussetzt
@@ -45,9 +45,11 @@ Es gibt keine direkte Reihenfolge, lediglich Themen die sich teilweise überschn
- Könnt auch gerne nachfragen wenn was nicht funktioniert! - Könnt auch gerne nachfragen wenn was nicht funktioniert!
- Dann könnt ihr einfach die Tests mit `pytest` in der Konsole aufrufen - Dann könnt ihr einfach die Tests mit `pytest` in der Konsole aufrufen
- Schlagen die Tests fehl sieht das so aus: - Schlagen die Tests fehl sieht das so aus:
![image not found](https://cloud.narl.io/s/8Dj4E79RKnHZQNJ/preview) ![image not found](https://cloud.narl.io/s/8Dj4E79RKnHZQNJ/preview)
- Hier sagt euch Pytest auch was alles nicht an eurem Code funktioniert - Hier sagt euch Pytest auch was alles nicht an eurem Code funktioniert
- Funktioniert euer Code sieht das so aus: - Funktioniert euer Code sieht das so aus:
![image not found](https://cloud.narl.io/s/2HGdaiQkP4YEQ5K/preview) ![image not found](https://cloud.narl.io/s/2HGdaiQkP4YEQ5K/preview)
## Kontakt ## Kontakt

View File

@@ -0,0 +1 @@
# primes generator

View File

View File

@@ -0,0 +1,29 @@
from typing import Iterator
def is_prime(n: int) -> bool:
if n < 2:
return False
for d in range(2, n // 2 + 1):
if n % d == 0:
return False
return True
def primes() -> Iterator[int]:
num = 2
while True:
if is_prime(num):
yield num
num += 1
def prime_factorize(n: int) -> Iterator[int]:
it = primes()
num = n
while num > 1:
if num % (prime := next(it)) != 0:
continue
num //= prime
it = primes()
yield prime

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
# List Comprehensions

View File

@@ -0,0 +1,36 @@
def divisible_by_7(n: int) -> list[int]:
"""
Returns a list of all numbers till 'n' that are divisible by '7'
"""
def contains_3(n: int) -> list[int]:
"""
Returns a list of all numbers that contain the digit '3' in them
"""
def count_spaces(string: str) -> int:
"""
Count the spaces in a string
"""
def remove_vowels(string: str) -> str:
"""
Remove all vowels from the string
"""
def word_lengths(string: str) -> dict[str, int]:
"""
Create a dictionary of all words with their lengths
"""
def prime_numbers(n: int) -> list[int]:
"""
Returns a list of all prime numbers till 'n' (HARD)
"""

View File

View File

@@ -0,0 +1,41 @@
def divisible_by_7(n: int) -> list[int]:
"""
Returns a list of all numbers till 'n' that are divisible by '7'
"""
return [x for x in range(1, n) if x % 7 == 0]
def contains_3(n: int) -> list[int]:
"""
Returns a list of all numbers that contain the digit '3' in them
"""
return [x for x in range(1, n) if '3' in str(x)]
def count_spaces(string: str) -> int:
"""
Count the spaces in a string
"""
return len([ch for ch in string if ' ' == ch])
def remove_vowels(string: str) -> str:
"""
Remove all vowels from the string
"""
return ''.join([ch for ch in string if ch.lower() not in 'aeiou'])
def word_lengths(string: str) -> dict[str, int]:
"""
Create a dictionary of all words with their lengths
"""
return {word: len(word) for word in string.split(' ') if len(word) > 0}
def prime_numbers(n: int) -> list[int]:
"""
Returns a list of all prime numbers till 'n' (HARD)
"""
return [x for x in range(2, n) if all(x % y != 0 for y in range(2, x))]

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
# [Primzahlen](./primes.py) # [Primzahlen](src/branch/main/loops/primes/primes.py)
## `is_prime` ## `is_prime`
@@ -28,4 +28,4 @@ Schreiben Sie nun folgende Funktion `prime_factorize(n: int) -> list[int]` welch
Tipp: Sie können hierfür die Funktionen `is_prime` und `next_prime` verwenden Tipp: Sie können hierfür die Funktionen `is_prime` und `next_prime` verwenden
## [Hier gehts zu den Lösungen](./solution/primes.py) ## [Hier gehts zu den Lösungen](src/branch/main/loops/primes/solution)

84
loops/sort/README.md Normal file
View File

@@ -0,0 +1,84 @@
# [Sortierte Datenstrukturen](src/branch/main/loops/sort/sort.py)
## `selection_sort`
**Selection Sort** basiert auf dem Konzept durch jedes Element in einer Liste zu gehen um dann das kleineste Element in den übrigen zu suchen und mit dem aktuellen Element zu tauschen.
- Wichtig ist dass dabei die übergebene Liste nicht verändert wird und eine neue sortierte erstellt wird
- Manuell erstellen mit loop oder `deepcopy`
Beispiel:
```
arr[] = 64 25 12 22 11
// Find the minimum element in arr[0...4]
// and place it at beginning
11 25 12 22 64
// Find the minimum element in arr[1...4]
// and place it at beginning of arr[1...4]
11 12 25 22 64
// Find the minimum element in arr[2...4]
// and place it at beginning of arr[2...4]
11 12 22 25 64
// Find the minimum element in arr[3...4]
// and place it at beginning of arr[3...4]
11 12 22 25 64
```
<details>
<summary>Hilfe 1: Pseudocode</summary>
```
for e_i in xs
kleinstes_e = e_i
for e_j in xs mit: j = i + 1
if kleinstes_e > e_j
kleinstes_e = e_j
vertausche e_i und kleinstes_e
```
</details>
## `binary_search`
Hierbei handelt es sich um einen Algorithmus welcher die Position von einem Wert in einem sortierten Array schnell findet.
Beispiele:
```python
binary_search([1, 2, 3, 4, 5], 4) # 3, was der index von 4 ist
binary_search(["a", "b", "c", "d"], "b") # 1, was der index von "b" ist
```
- Dazu definieren wir eine linke Grenze `left` mit dem Anfangswert `0` und eine rechte Grenze `right` mit dem Anfangswert `len(xs) - 1`, damit können wir unser gesuchtes Element immer weiter eingrenzen.
- Jetzt wissen wir durch die Sortierung dass `left <= right` sein muss.
- Also gehen wir jetzt durch unsere Liste und berechnen die Mitte `middle` von `left` und `right` aus und vergleichen diese mit unserem gesuchten Wert.
- Ist `middle` kleiner als unser Wert dann können wir `left = middle + 1` setzen
- Ist `middle` größer als unser Wert dann können wir `right = middle - 1` setzen
- Sonst haben wir unseren Wert, nämlich `middle`, gefunden und können diesen zurückgeben
- Wenn der Wert nicht existiert wird `None` zurückgegeben
- Für leere Listen soll auch `None` zurückgegeben werden
<details>
<summary>Hilfe 1: Pseudocode</summary>
```
linker_index = 0
rechter_index = länge - 1
solange linker_index <= rechter_index dann
mitte = (linker_index + rechter_index) / 2
Wenn Liste[mitte] < gesuchter Wert dann
linker_index = mitte + 1
Wenn Liste[mitte] > gesuchter Wert dann
rechter_index = mitte - 1
Sonst
return Liste[mitte]
return Nichts
```
</details>
## [Hier gehts zur Lösung](src/branch/main/loops/sort/solution)

View File

@@ -0,0 +1,87 @@
# Solution
## `selection_sort`
Zunächst müssen wir eine neue Liste mit den selben Elementen erstellen, am schnellsten geht das mit `copy.deepcopy` welche eine vollständige Copie erstellt.
```python
from copy import deepcopy
xss = deepcopy(xs)
```
Wir müssen durch jedes Element gehen, also
```python
for i in range(len(xss)):
# ...
```
Nun wollen wir in den übrigen Elementen ($j = i + 1$) das kleinste finden
```python
for i in range(len(xss)):
min_i = i # index vom kleinsten Element,
# das aktuelle i falls dieses schon das kleinste ist
for j in range(i + 1, len(xss)):
# ...
```
Jetzt vergleichen wir nur noch jedes j-te Element mit dem aktuellen kleinsten
```python
for i in range(len(xss)):
min_i = i # index vom kleinsten Element,
# das aktuelle i falls dieses schon das kleinste ist
for j in range(i + 1, len(xss)):
if xss[j] < xss[min_i]:
min_i = j # kleineres element gefunden
```
Nun können wir einfach das i-te mit dem min_i vertauschen (entweder ist es i oder wir haben ein kleineres gefunden)
```python
xss[i], xss[min_i] = xss[min_i], xss[i] # tauschen i mit min_i
```
und am Ende können wir `xss` zurückgeben
```python
return xss
```
## `binary_search`
Hierfür definieren wir zunächst `left = 0` und `right = len(xs) - 1`, dann können wir die Schleifenbedingung definieren als
```python
while left <= right:
# ...
```
weil sobald diese nicht mehr gilt konnten wir den Wert nicht finden. (Links und Rechts tauschen) und wir können `None` zurückgeben.
Nun berechnen wir den mittleren Index mit dem integer division (oder auch floor weil es die Zahl hinterm Komma verwirft).
```python
middle = (left + right) // 2
```
Nun müssen wir nur noch `xs[middle]` mit `value` vergleichen
```python
if xs[middle] < value:
left = middle + 1
elif xs[middle] > value:
right = middle - 1
```
Und wenn `xs[middle] == value` ist haben wir unseren Index `middle` gefunden.
```python
if xs[middle] < value:
left = middle + 1
elif xs[middle] > value:
right = middle - 1
else:
return middle
```

View File

@@ -0,0 +1,27 @@
from copy import deepcopy
from typing import Iterator, Optional
def selection_sort[T](xs: Iterator[T]) -> Iterator[T]:
length = len(xs)
xss = deepcopy(xs)
for i in range(length):
min_i = i
for j in range(i + 1, length):
if xss[j] < xss[min_i]:
min_i = j
xss[i], xss[min_i] = xss[min_i], xss[i]
return xss
def binary_search[T](xs: list[T], value: T) -> Optional[int]:
left = 0
right = len(xs) - 1
while left <= right:
middle = (left + right) // 2
if xs[middle] < value:
left = middle + 1
elif xs[middle] > value:
right = middle - 1
else:
return middle
return None

9
loops/sort/sort.py Normal file
View File

@@ -0,0 +1,9 @@
from typing import Iterator, Optional
def selection_sort[T](xs: Iterator[T]) -> Iterator[T]:
return []
def binary_search[T](xs: list[T], value: T) -> Optional[int]:
return None

22
loops/sort/test_sort.py Normal file
View File

@@ -0,0 +1,22 @@
from random import randint
from typing import Iterator
from sort import selection_sort, binary_search
def get_random_collection(min: int, max: int, size: int) -> Iterator[int]:
return [randint(min, max) for _ in range(size)]
def test_selection_sort():
xs = [5, 4, 3, 2, 1, 0]
assert list(selection_sort(xs)) == sorted(xs)
assert xs == [5, 4, 3, 2, 1, 0], "list was modified in `selection_sort` return a copy instead"
xs = get_random_collection(0, 100, 100)
print(xs)
assert list(selection_sort(xs)) == sorted(xs)
def test_binary_search():
xs = sorted(set(get_random_collection(0, 10000, 100)))
for i, e in enumerate(xs):
assert binary_search(xs, e) == i
assert binary_search([], 1) == None
assert binary_search([2], 1) == None
assert binary_search([2, 3], 1) == None

View File

@@ -0,0 +1,4 @@
# Mit Zeichenketten arbeiten und manipulieren
Diese Teilaufgaben sind teilweise sehr einfach zu implementieren und sollen veranschaulichen was man alles mit Strings machen kann. Hierbei könnt ihr euch es natürlich einfach machen und die Buildins von `str` verwenden oder die Funktionen komplett selber implementieren.

View File

@@ -0,0 +1,93 @@
from dataclasses import dataclass, InitVar
from typing import Iterator
type Str = 'String' | str
@dataclass
class String:
_s: InitVar[str]
def __post_init__(self, s: str) -> None:
self.__s = s
def __str__(self) -> str:
return self.__s
def __add__(self, other: Str) -> 'String':
return String(self.__s + str(other))
def __iadd__(self, other: Str) -> 'String':
return self + other
def __len__(self) -> int:
return len(self.__s)
def __eq__(self, other: Str) -> bool:
return str(self) == str(other)
def concat(self, other: Str) -> None:
self + other
def contains(self, other: Str) -> bool:
s = str(other)
for c in str(self):
if len(s) <= 0:
break
elif c == s[0]:
s: str = s[1:]
else:
s = str(other)
return len(s) == 0
def concat(self, other: Str) -> None:
self.__s += str(other)
def substring(self, start: int, end: int) -> 'String':
substr: str = ""
for i, c in enumerate(self.__s):
if i >= start and i <= end:
substr += c
return substr
def strip(self, chars: Str = ' ' + '\n' + '\t' + '\r') -> None:
i = 0
while i < len(self) and self.__s[i] in chars:
i += 1
j: int = len(self) - 1
while i <= j and self.__s[j] in chars:
j -= 1
self.__s: str = str(self)[i:j + 1]
def replace(self, old: Str, new: Str, count = -1) -> None:
o = str(old)
n = str(new)
j = 0
while count > 0 or (count < 0 and j < len(self)):
i: int = j
while len(o) > 0 and j < len(self):
if o[0] == self.__s[j]:
o: str = o[1:]
j += 1
else:
j += 1
break
if len(o) <= 0:
self.__s = self.__s[:i] + n + self.__s[j:]
j += len(new) - len(old)
count -= 1
o = str(old)
def add_prefix(self, prefix: Str) -> None:
self.__s = str(prefix) + self.__s
def add_suffix(self, suffix: Str) -> None:
self.__s += str(suffix)
def join[T](self, xs: Iterator[T]) -> 'String':
output = String("")
length: int = len(xs)
for i, e in enumerate(xs):
output += str(e)
if i < length - 1:
output += self
return output

View File

@@ -0,0 +1,9 @@
from dataclasses import dataclass
# kleine Hilfestellung mit `Str` kann man sowohl `str` als auch `String` meinen
type Str = 'String' | str
@dataclass
class String:
# Implement!
pass

View File

@@ -0,0 +1,49 @@
from strings import String
def test_eq_for_str():
test_str = String("this is a test string!")
assert test_str == "this is a test string!", "__eq__ wasn't implemented correctly for `String` and `str`"
def test_strings_contains():
test_str = String("this is a test")
assert test_str.contains("this")
assert not test_str.contains("release")
def test_strings_concat():
test_str = String("")
test_str += "test succesful!"
assert test_str == "test succesful!"
test_str.concat(" Or is it?")
assert test_str == "test succesful! Or is it?"
def test_strings_strip():
test_str = String(" halo? \n")
test_str.strip()
assert test_str == "halo?"
test_str = String(" \n ")
test_str.strip()
assert test_str == ""
def test_strings_replace():
test_str = String("har har har, try replacing thhis")
test_str.replace('har ', 'ha')
assert test_str == "hahahar, try replacing thhis"
test_str.replace('r', '', 1)
assert test_str == "hahaha, try replacing thhis"
test_str.replace('hh', 'h')
assert test_str == "hahaha, try replacing this"
test_str.replace('try replacing this', "replaced")
assert test_str == "hahaha, replaced"
def test_add_pre_suf():
test_str = String(" ")
test_str.add_suffix("suff")
assert test_str == " suff"
test_str.add_prefix("pref")
assert test_str == "pref suff"
def test_join():
assert String(", ").join([1, 2, 3, 4]) == "1, 2, 3, 4"
assert String(", ").join([]) == ""