Lab 6.1 python code

0.0(0)
Studied by 0 people
call kaiCall Kai
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
GameKnowt Play
Card Sorting

1/34

encourage image

There's no tags or description

Looks like no tags are added yet.

35 Terms

1
New cards

import copy

Haalt de module copy binnen. Die heb je nodig voor copy.deepcopy, een echte kopie van data (taak 2)

2
New cards

from datetime import datetime

Haalt de klasse datetime uit de module datetime binnen. Daarmee zet je tekst zoals "3/18/25" om naar een echte datum waarmee je kunt rekenen (taak 4). Dit is de import uit de hint van de opdracht. Op de plek van _datetime kan gewoon datetime.

3
New cards

DATE_FORMAT = "%m/%d/%y" # bv. 9/28/25

Een variabele met het datumformaat in jullie bestanden: %m is de maand, %d de dag en %y het jaar met twee cijfers (25). De naam is in hoofdletters omdat het een constante is die niet verandert. Als het formaat ooit anders is, hoef je het maar op één plek aan te passen.

4
New cards

def read_file(filename):

Definieert een functie met de naam read_file. Ze krijgt één invoer, filename (bijvoorbeeld "books.txt").

5
New cards

with open(filename, "r", encoding="utf-8") as f:

Opent het bestand.

  • "r" staat voor read (alleen lezen).

  • encoding="utf-8" zorgt dat speciale tekens goed gelezen worden.

  • with ... as f zorgt dat het bestand automatisch netjes gesloten wordt als het blok klaar is. Het bestand heet binnen het blok f.


6
New cards

lines = [line.strip() for line in f if line.strip()]

Een list comprehension die het bestand regel voor regel doorloopt.

  • for line in f: pak elke regel uit het bestand.

  • line.strip(): haalt spaties en het enter-teken (\n) aan begin en eind weg.

  • if line.strip(): een lege regel wordt na strip() een lege string, en die telt als “onwaar”. Lege regels vallen er dus uit.

Resultaat: een lijst met schone tekstregels, bijvoorbeeld ["book_id,title,author", "B001,Lord of the Rings,Charles Dickens", ...].

7
New cards

rows = [[field.strip() for field in line.split(",")] for line in lines]

Een list comprehension in een list comprehension.

  • De buitenste loop pakt elke regel uit lines.

  • line.split(",") knipt de regel bij elke komma in stukjes. "B001,Lord of the Rings,Charles Dickens" wordt ["B001", "Lord of the Rings", "Charles Dickens"].

  • De binnenste loop haalt van elk stukje de spaties weg.

Resultaat: een lijst van lijsten, een rij per regel en een kolom per stukje.

8
New cards

return rows[1:] # eerste regel is de koptekst

Geeft het resultaat terug aan degene die de functie aanroept. rows[1:] betekent “alles vanaf index 1”. Index 0 is de koptekst (book_id,title,author), die wil je niet als echt boek zien. Die wordt dus overgeslagen.

9
New cards

def pad_borrowed(borrowed):

return [row + [""] * (4 - len(row)) for row in borrowed]

Dit is een veiligheidsnet. Elke rij in borrowed.txt moet 4 kolommen hebben: student, boek, datum geleend, datum terug. Als een regel zonder de laatste komma eindigt (S065,B028,9/28/25), zou de rij maar 3 stukjes hebben en zou r[3] crashen.

  • len(row) is het aantal kolommen in de rij.

  • 4 - len(row) is het aantal ontbrekende kolommen (0 of 1).

  • [""] * 1 geeft [""], een lijst met één lege string. [""] * 0 geeft een lege lijst.

  • row + [...] plakt die erachter.

Een rij die al compleet is, blijft dus gelijk. Een rij met een ontbrekende kolom krijgt een lege date_returned.

10
New cards

def map_books_students(books, students, borrowed):

Functie met drie invoerlijsten.

11
New cards

student_names = dict(zip([s[0] for s in students], [s[1] for s in students]))

Hier staan vier dingen in één regel:

  1. [s[0] for s in students] is een lijst van alle student-id’s (["S001", "S002", ...]). s[0] is de eerste kolom van elke rij.

  2. [s[1] for s in students] is een lijst van alle namen (["Nina Wilson", "Sam Brown", ...]).

  3. zip(...) plakt die twee aan elkaar tot paren ("S001", "Nina Wilson"), enzovoort.

  4. dict(...) maakt er een woordenboek van: {"S001": "Nina Wilson", "S002": "Sam Brown", ...}.

Daarmee kun je met een id direct de naam opzoeken: student_names["S002"] geeft "Sam Brown".

12
New cards

book_titles = dict(zip([b[0] for b in books], [b[1] for b in books]))

Hetzelfde voor de boeken: {"B001": "Lord of the Rings", ...}. Je koppelt op id omdat namen en titels niet uniek zijn (er zijn meerdere “Sam Davis”).

13
New cards

return [(student_names[r[0]], book_titles[r[1]]) for r in borrowed]

Voor elke uitleenregel r:

  • r[0] is het student-id. student_names[r[0]] zoekt de naam op.

  • r[1] is het boek-id. book_titles[r[1]] zoekt de titel op.

  • Samen vormen ze een paar (naam, titel).

De functie geeft een lijst van alle paren terug.

14
New cards

def currently_borrowed(borrowed):

borrowed_copy = copy.deepcopy(borrowed) # origineel blijft ongewijzigd

Maakt een volledig onafhankelijke kopie. borrowed is een lijst van lijsten. Bij een gewone toewijzing (b2 = borrowed) wijzen beide namen naar dezelfde data, dus een wijziging via b2 verandert ook borrowed. deepcopy kopieert ook alle lijsten binnenin, zodat het origineel veilig blijft.

15
New cards

current = [r for r in borrowed_copy if r[3] == ""]

List comprehension met filter: houd alleen de rijen waar kolom 3 (date_returned) leeg is. Dat zijn de boeken die nog uitgeleend zijn.

16
New cards

returned = [r for r in borrowed_copy if r[3] != ""]

Het omgekeerde: rijen waar wél een terugbrengdatum staat.

17
New cards

return current, returned

Geeft beide lijsten tegelijk terug. Python stopt ze automatisch in een tuple (een vast paar), dat je later weer uit elkaar haalt.

18
New cards

def frequent_borrowers(students, borrowed, minimum=2):

minimum=2 is een standaardwaarde: als je niets meegeeft, geldt “minstens 2 boeken”, precies wat de opdracht vraagt.

19
New cards

student_ids = [r[0] for r in borrowed]

Een lijst met het student-id van elke uitleenregel. Een student die drie keer leent, staat er dus drie keer in.

20
New cards

counts = {sid: student_ids.count(sid) for sid in set(student_ids)}

Een dictionary comprehension.

  • set(student_ids) haalt dubbelen weg, dus elk id komt één keer voor.

  • student_ids.count(sid) telt hoe vaak dat id in de volledige lijst staat.

  • Resultaat: bijvoorbeeld {"S002": 3, "S005": 3, "S065": 2, ...}.


21
New cards

return [(s[0], s[1], s[2], counts[s[0]]) for s in students

if counts.get(s[0], 0) >= minimum], counts

  • for s in students doorloopt alle studenten.

  • counts.get(s[0], 0) zoekt het aantal op. Heeft een student nooit geleend, dan staat hij niet in counts, en .get(..., 0) geeft dan 0 in plaats van een foutmelding.

  • if ... >= minimum houdt alleen de studenten met minstens 2 boeken.

  • Per student maak je een tuple (id, naam, afdeling, aantal).

De functie geeft twee dingen terug: de lijst met frequente leners en de volledige counts.

22
New cards

def borrow_durations(books, returned):

book_titles = dict(zip([b[0] for b in books], [b[1] for b in books]))

Dezelfde id-naar-titel dictionary als in taak 1.

23
New cards

durations = [

(datetime.strptime(r[3], DATE_FORMAT).date()

- datetime.strptime(r[2], DATE_FORMAT).date()).days

for r in returned

]

Een list comprehension die voor elke teruggebrachte boekregel r de leenduur uitrekent:

  • datetime.strptime(r[3], DATE_FORMAT) zet de tekst van de terugbrengdatum ("3/29/25") om naar een datumobject. Het formaat vertelt Python hoe de tekst is opgebouwd.

  • .date() houdt alleen de datum over, zonder tijd.

  • Hetzelfde voor r[2], de leendatum.

  • Twee datums van elkaar aftrekken geeft een tijdverschil (timedelta). .days maakt daar het aantal dagen van.

Dit is het voorbeeld uit de hint ((date_1 - date_2).days), maar dan voor alle rijen tegelijk.

24
New cards

titles = [book_titles[r[1]] for r in returned]

De bijbehorende titel bij elke teruggebrachte rij, in dezelfde volgorde als durations

25
New cards

pairs = list(zip(titles, durations)) # (boek, aantal dagen)

zip plakt titel en duur aan elkaar tot paren zoals ("The Great Gatsby", 3). list(...) maakt er een echte lijst van, omdat zip zelf maar een “stroom” levert die je één keer kunt doorlopen.

26
New cards

average = sum(durations) / len(durations) if durations else 0

Het gemiddelde is de som van alle dagen gedeeld door het aantal. if durations else 0 voorkomt delen door nul als er geen teruggebrachte boeken zijn: dan wordt het gemiddelde 0.

27
New cards

return pairs, average

Geeft de lijst met paren en het gemiddelde terug.

28
New cards

def main():

books = read_file("books.txt")

students = read_file("students.txt")

borrowed = pad_borrowed(read_file("borrowed.txt"))

Leest de drie bestanden in. Bij borrowed wordt het resultaat meteen door pad_borrowed gehaald voor het veiligheidsnet.

29
New cards

print("=== 1. Book-Student mapping ===")

for name, title in map_books_students(books, students, borrowed):

print(f"{name} borrowed '{title}'")

Print een kopje en roept taak 1 aan. De for loop pakt elk paar uit de lijst en splitst het meteen in name en title (unpacking). De f"..." is een f-string: alles tussen { } wordt vervangen door de waarde van die variabele.

30
New cards

current, returned = currently_borrowed(borrowed)

print("\n=== 2. Currently borrowed ===")

for name, title in map_books_students(hoeken, students, current):

print(f"{name} still has '{title}'")

Taak 2 geeft twee lijsten terug, die je hier in current en returned uit elkaar haalt. \n in de tekst is een lege regel. Voor het tonen hergebruik je map_books_students, maar nu met alleen de huidige uitleningen.

31
New cards

frequent, counts = frequent_borrowers(students, borrowed)

print("\n=== 3. Frequent borrowers (>= 2 books) ===")

for sid, name, dept, count in frequent:

print(f"{sid} - {name} ({dept}): {count} books")

Roept taak 3 aan en print per frequente lener id, naam, afdeling en aantal boeken.

32
New cards

pairs, average = borrow_durations(books, returned)

print("\n=== 4. Borrow durations (returned books) ===")

for title, days in pairs:

print(f"'{title}': {days} days")

print(f"Average duration: {average:.2f} days")

Roept taak 4 aan met de lijst returned uit taak 2. {average:.2f} toont het gemiddelde met 2 cijfers achter de komma (14.63).

33
New cards

if name == "__main__":

main()

Python zet in de speciale variabele __name__ de waarde "__main__" als je dit bestand direct runt. Wordt het bestand geïmporteerd door een ander script, dan heeft __name__ een andere waarde. Deze regel betekent dus: “start main() alleen als dit bestand zelf wordt uitgevoerd.”

34
New cards

import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

  • __file__ is het pad van het script zelf.

  • os.path.abspath(...) maakt er een volledig pad van.

  • os.path.dirname(...) houdt alleen de map over waarin het script staat.


35
New cards

path = os.path.join(BASE_DIR, filename)

Plakt die map en de bestandsnaam aan elkaar tot een volledig pad. Zo vindt het script de bestanden altijd, ook als PyCharm een andere werkmap gebruikt.