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
Πληροφορική Ι
Εβδομάδα 13 · Λεξικά (Dictionaries)
(Οδηγίες χρήσης του διαδραστικού κώδικα: δείτε την αρχική σελίδα.)
1 Λεξικά (Dictionaries)
1.1 Δημιουργία και βασική πρόσβαση
Μια λίστα (Εβδομάδα 4) συσχετίζει τιμές με δείκτες-ακέραιους (0, 1, 2, ...). Ένα λεξικό (dictionary) είναι πιο γενικό: συσχετίζει τιμές με κλειδιά (keys) της επιλογής μας — συμβολοσειρές, αριθμούς, ή γενικά οποιονδήποτε αμετάβλητο (immutable) τύπο (Εβδομάδα 1). Κάθε στοιχείο ενός λεξικού είναι λοιπόν ένα ζεύγος κλειδιού-τιμής (key-value pair):
Σε αντίθεση με τις λίστες, τα λεξικά δεν είναι αλληλουχίες με σειρά — δεν έχει νόημα να ρωτήσουμε “ποιο είναι το πρώτο στοιχείο;”. Αν ζητήσουμε ένα κλειδί που δεν υπάρχει, προκαλείται σφάλμα 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).
⤺ Πίσω στην αρχική σελίδα / πρόγραμμα μαθήματος · Διαφάνειες αυτής της εβδομάδας