Τμήμα Μαθηματικών

Πληροφορική Ι

Εβδομάδα 13 · Λεξικά (Dictionaries)

(Οδηγίες χρήσης του διαδραστικού κώδικα: δείτε την αρχική σελίδα.)

1 Λεξικά (Dictionaries)

1.1 Δημιουργία και βασική πρόσβαση

Μια λίστα (Εβδομάδα 4) συσχετίζει τιμές με δείκτες-ακέραιους (0, 1, 2, ...). Ένα λεξικό (dictionary) είναι πιο γενικό: συσχετίζει τιμές με κλειδιά (keys) της επιλογής μας — συμβολοσειρές, αριθμούς, ή γενικά οποιονδήποτε αμετάβλητο (immutable) τύπο (Εβδομάδα 1). Κάθε στοιχείο ενός λεξικού είναι λοιπόν ένα ζεύγος κλειδιού-τιμής (key-value pair):

flowchart LR
    subgraph λίστα
        i0["0"] --> v0["'555-1111'"]
        i1["1"] --> v1["'555-2222'"]
    end
    subgraph λεξικό
        k0["'Chris'"] --> w0["'555-1111'"]
        k1["'Kate'"] --> w1["'555-2222'"]
    end

Σε αντίθεση με τις λίστες, τα λεξικά δεν είναι αλληλουχίες με σειρά — δεν έχει νόημα να ρωτήσουμε “ποιο είναι το πρώτο στοιχείο;”. Αν ζητήσουμε ένα κλειδί που δεν υπάρχει, προκαλείται σφάλμα KeyError:

1.2 Έλεγχος ύπαρξης κλειδιού: in, και η μέθοδος get

Για να αποφύγουμε το KeyError, ελέγχουμε πρώτα αν υπάρχει το κλειδί με τον τελεστή in (τον ίδιο τελεστή που είδαμε σε συμβολοσειρές και λίστες):

Πιο συνοπτικά, η μέθοδος get(κλειδί, προεπιλογή) επιστρέφει την τιμή του κλειδιού αν υπάρχει, αλλιώς την προεπιλεγμένη τιμή που δίνουμε, χωρίς κανένα σφάλμα:

1.3 Τροποποίηση: προσθήκη, ενημέρωση, διαγραφή

Τα λεξικά είναι μεταβλητά (mutable) αντικείμενα (Εβδομάδα 1, Εβδομάδα 4): η ίδια εντολή εκχώρησης λεξικό[κλειδί] = τιμή προσθέτει ένα νέο ζεύγος (αν το κλειδί δεν υπάρχει) ή ενημερώνει το υπάρχον (αν υπάρχει). Η εντολή del αφαιρεί ένα ζεύγος:

1.4 Επανάληψη σε λεξικό: keys(), values(), items()

Ένας βρόχος for πάνω σε λεξικό διατρέχει από προεπιλογή τα κλειδιά του. Οι μέθοδοι keys(), values(), items() δίνουν ρητά πρόσβαση στα κλειδιά, στις τιμές, ή σε ζεύγη (κλειδί, τιμή) αντίστοιχα — το τελευταίο συνδυάζεται φυσικά με την ταυτόχρονη εκχώρηση πολλών μεταβλητών (Εβδομάδα 1):

1.5 Χαρακτηριστικό της Python: λεξικά με κατανόηση (dict comprehensions)

Όπως οι λίστες με κατανόηση (Εβδομάδα 4), υπάρχει και το αντίστοιχο συνοπτικό ιδίωμα για λεξικά, με τη μορφή {κλειδί: τιμή for ... }:

1.6 Καταμέτρηση συχνότητας χαρακτήρων

Ένα κλασικό πρόβλημα όπου τα λεξικά είναι το φυσικό εργαλείο: πόσες φορές εμφανίζεται κάθε χαρακτήρας σε ένα κείμενο; Χρησιμοποιούμε το χαρακτήρα ως κλειδί, και το πλήθος εμφανίσεών του ως τιμή, ενημερώνοντάς το με τη get (ώστε να μη χρειάζεται να ελέγχουμε ρητά αν το κλειδί υπάρχει ήδη):

Το ίδιο λεξικό ως ραβδόγραμμα (γράφημα με το matplotlib):

Η sorted(..., key=lambda item: -item[1]) ταξινομεί τα ζεύγη (κλειδί, τιμή) κατά φθίνουσα συχνότητα — το lambda ορίζει μια ανώνυμη, “μιας χρήσης” συνάρτηση που λέει στην sorted να συγκρίνει τα ζεύγη με βάση το δεύτερο στοιχείο τους (item[1], δηλαδή το πλήθος), με πρόσημο - ώστε η ταξινόμηση να είναι φθίνουσα αντί για αύξουσα.

1.7 Memoization με λεξικό, ξανά

Στην Εβδομάδα 9 χρησιμοποιήσαμε το έτοιμο @functools.lru_cache για memoization της αναδρομικής Fibonacci. Τώρα που ξέρουμε λεξικά, μπορούμε να δούμε τι κάνει “από μέσα”: κρατάει ένα λεξικό όπου το κλειδί είναι το όρισμα, και η τιμή το ήδη υπολογισμένο αποτέλεσμα:

Σημείωση

Στην Εβδομάδα 6 είδαμε ότι τα μεταβλητά προεπιλεγμένα ορίσματα (όπως το cache={}) είναι συνήθως παγίδα: το ίδιο αντικείμενο επιβιώνει από κλήση σε κλήση.

Εδώ όμως αυτό ακριβώς το χαρακτηριστικό είναι επιθυμητό — θέλουμε το cache να θυμάται τα αποτελέσματα ανάμεσα στις (αναδρομικές) κλήσεις της fib_memo.

2 Σύνοψη

Σε αυτή την εβδομάδα είδαμε:

  • Λεξικά: δημιουργία, πρόσβαση με κλειδί, KeyError, και τους ασφαλέστερους τρόπους in και get.
  • Τροποποίηση λεξικών: προσθήκη, ενημέρωση, διαγραφή.
  • Επανάληψη με keys(), values(), items(), και λεξικά με κατανόηση.
  • Τεχνική καταμέτρησης συχνοτήτων με λεξικό, και memoization με λεξικό (τι κάνει “από μέσα” το lru_cache της Εβδομάδας 9).

⤺ Πίσω στην αρχική σελίδα / πρόγραμμα μαθήματος  ·  Διαφάνειες αυτής της εβδομάδας