Γλώσσες Προγραμματισμού Εφαρμογών - ΜΕΠΒ20 Διάλεξη 7 Λεξικά (Dictionaries) Παπαϊωάννου Αθανάσιος Π.Μ.Σ. «Εφαρμοσμένη Πληροφορική» Χειμερινό Εξάμηνο 20 16-20 17
Τι είναι μια Συλλογή; Μία συλλογή έχει το πλεονέκτημα ότι μεταφέρει πολλαπλές τιμές πρακτικά τακτοποιημένες σε ένα πακέτο. Έχουμε πολλαπλές τιμές κάτω από μία μεταβλητή Το πετυχαίνουμε με το να έχουμε περισσότερες θέσεις εντός της μεταβλητής Υπάρχουν τρόποι αναζήτησης των διαφορετικών θέσεων εντός της μεταβλητής
Τι δεν είναι Συλλογή Οι περισσότερες μεταβλητές αποθηκεύουν μία τιμή εντός τους- όταν θέτουμε νέα τιμή στην μεταβλητή, η παλιά τιμή χάνεται (επανεγγράφεται) $ python Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:01:18) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> x = 2 >>> x = 4 >>> print(x) 4
Η ιστορία δύο συλλογών... Λίστα Γραμμική συλλογή τιμών που κρατάει τη σειρά Λεξικό Τσάντα με τιμές, όπου καθεμιά έχει την ετικέτα της
Μειονεκτήματα των Λιστών Μέχρι τώρα είδαμε έχουμε δει τις λίστες που μπορούν να αναπαραστήσουν ένα δυναμικό σύνολο από τιμές ή άλλες λίστες Αλλά οι λίστες έχουν και κάποιες αδυναμίες Συγκεκριμένα, η αναζήτηση σε μια λίστα παίρνει πολύ χρόνο Πρέπει να διατρέξουμε κάθε στοιχείο και να ελέγξουμε αν είναι αυτό που θέλουμε Αυτό είναι πρόβλημα αν αυτό που θέλουμε να κάνουμε είναι απλώς να του αλλάξουμε την τιμή
Μειονεκτήματα των Λιστών Τί γίνεται αν δε γνωρίζουμε πολλά για τα στοιχεία που θέλουμε να βάλουμε στη λίστα; Μπορούμε να δημιουργήσουμε μια κενή λίστα και να τη γεμίσουμε δυναμικά Όμως, τι κάνουμε αν έχουμε διπλές εγγραφές; Μπορούμε να διατρέξουμε τη λίστα αφού τη δημιουργήσουμε και να διαγράψουμε τις διπλές εγγραφές Αργό Επίσης, και πάλι δεν μπορούμε να δεικτοδοτήσουμε τις λίστες με βάση τα δεδομένα Οπότε όχι list_name[data], παρά μόνο list_name[i]
Παράδειγμα Πολύ αναζήτηση γίνεται με βάση τον αριθμό λέξεων Σε στατικές βάσεις δεδομένων όπως τα επιστημονικά περιοδικά αλλά και στο google για την ταξινόμηση των ιστοσελίδων με βάση τη συνάφειά τους με την αναζητούμενη λέξη Οπότε, κάθε αρχείο διαβάζεται και μετρώνται οι λέξεις του και μετά οι μετρητές κανονικοποιούνται Συναφή αρχεία θα πρέπει να έχουν παρόμοιους κανονικοποιημένους μετρητές λέξεων Αλλά οι λέξεις με τις οποίες θα γίνει η αναζήτηση δεν είναι γνωστές εκ των προτέρων
Λεξικά χαρτομάντηλα κομπιουτεράκι άρωμα χρήματα γλυκό http:/ / en.wikipedia.org/ wiki/ Associative_array
Λεξικά Τα Λεξικά είναι η πιο δυνατή συλλογή της Python Τα Λεξικά μας επιτρέπουν να κάνουμε στην Python γρήγορες ενέργειες, παρόμοιες με αυτές σε βάσεις δεδομένων Τα Λεξικά απαντώνται με διαφορετικά ονόματα σε διαφορετικές γλώσσες: Associative Arrays - Perl / PHP Properties ή Map ή HashMap - Java Property Bag - C# /.Net http:/ / en.wikipedia.org/ wiki/ Associative_array
Λεξικά Οι Λίστες στοιχειοθετούν τις εγγραφές βάσει της σειράς τους στην λίστα Τα Λεξικά είναι σαν τσάντες - δεν υπάρχει σειρά Έτσι, στοιχειοθετούμε αυτά που τοποθετούμε σε ένα Λεξικό με μια ετικέτα αναζήτησης >>> purse = dict() >>> purse['money'] = 12 >>> purse['candy'] = 3 >>> purse['tissues'] = 75 >>> print(purse) {'money': 12, 'tissues': 75, 'candy': 3} >>> print(purse['candy']) 3 >>> purse['candy'] = purse['candy'] + 2 >>> print(purse) {'money': 12, 'tissues': 75, 'candy': 5}
Γιατί Λεξικά; Τα λεξικά είναι χρήσιμα αν θέλεις να αποθηκεύσεις πραγματικά μεγάλες αραιές δομές δεδομένων Μπορεί κανείς να υλοποιήσει φυλλομετρητές ή συναγερμούς με λεξικά Ή αν θέλει κανείς να αποθηκεύσει έναν μεγάλο όγκο δεδομένων αλλά δεν είναι σίγουρος για το πόσο μεγάλος είναι Οπότε για ένα σύνολο ονομάτων τον οποίων τον αριθμό δεν ξέρεις
Λεξικά Τα λεξικά δεν είναι ταξινομήμένα Τα κλειδιά των λεξικών πρέπει να είναι αμετάβλητα αντικείμενα (όπως συμβολοσειρές, αριθμούς, πλειάδες(!)), αλλά οι τιμές μπορεί να είναι οτιδήποτε Αν έχει δημιουργηθεί ένα λεξικό μπορεί κανείς να προσθέσει ζεύγη κλειδιώντιμών με ανάθεση μιας τιμής σε ένα κλειδί dictionary_name[key] = value Τα κλειδιά πρέπει να είναι μοναδικά
Συγκρίνοντας Λίστες και Λεξικά Τα Λεξικά είναι σαν Λίστες εκτός από το οτι χρησιμοποιούν κλειδιά αντί για αριθμούς για την αναζήτηση τιμών >>> lst = list() >>> lst.append(21) >>> lst.append(183) >>> print(lst) [21, 183] >>> lst[0] = 23 >>> print(lst) [23, 183] >>> ddd = dict() >>> ddd['age'] = 21 >>> ddd['course'] = 182 >>> print(ddd) {'course': 182, 'age': 21} >>> ddd['age'] = 23 >>> print(ddd) {'course': 182, 'age': 23}
>>> lst = list() >>> lst.append(21) >>> lst.append(183) >>> print(lst) [21, 183] >>> lst[0] = 23 >>> print(lst) [23, 183] Λίστα Κλειδί Τιμή [0] 21 [1] 18 3 lst >>> ddd = dict() >>> ddd['age'] = 21 >>> ddd['course'] = 182 >>> print(ddd) {'course': 182, 'age': 21} >>> ddd['age'] = 23 >>> print(ddd) {'course': 182, 'age': 23} Λεξικό Κλειδί Τιμή ['course'] 18 3 ['age'] 21 ddd
Σταθερές σε Λεξικά Οι σταθερές λεξικών χρησιμοποιούν αγκύλες και έχουν ζεύγη κλειδί : τιμή Μπορούμε να φτιάξουμε ένα κενό Λεξικό με την χρήση κενών αγκυλών >>> jjj = { 'chuck' : 1, 'fred' : 42, 'jan': 100} >>> print(jjj) {'jan': 100, 'chuck': 1, 'fred': 42} >>> ooo = { } >>> print(ooo) {} >>>
Το πιο συχνό όνομα; marquard zhen csev zhen cwen marquard zhen csev cwen zhen csev marquard zhen
Το πιο συχνό όνομα;
Το πιο συχνό όνομα; marquard zhen csev zhen cwen marquard zhen csev cwen zhen csev marquard zhen
Πολλοί μετρητές με ένα Λεξικό Συνηθισμένη χρήση ενός Λεξικού είναι καταμέτρηση του πόσο συχνά συναντάμε κάτι >>> ccc = dict() >>> ccc['csev'] = 1 >>> ccc['cwen'] = 1 >>> print(ccc) {'csev': 1, 'cwen': 1} >>> ccc['cwen'] = ccc['cwen'] + 1 >>> print(ccc) {'csev': 1, 'cwen': 2} Κλειδί Τιμή
Σφάλματα Λεξικών Είναι σφάλμα να αναφερθούμε ένα κλειδί που δεν υπάρχει στο λεξικό Μπορούμε να χρησιμοποιήσουμε τον τελεστή in για να ελέγξουμε εάν ένα κλειδί υπαρχει στο λεξικό >>> ccc = dict() >>> print(ccc['csev']) Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'csev' >>> print('csev' in ccc) False
Όταν συναντάμε ένα νέο όνομα Όταν συναντάμε ένα νέο όνομα, πρέπει να εισάγουμε μια νέα εγγραφή στο λεξικό και εάν είναι η δεύτερη ή τρίτη φορά που συναντάμε το όνομα, απλά προσθέτουμε ένα στον μετρητή του λεξικού για αυτό το όνομα counts = dict() names = ['csev', 'cwen', 'csev', 'zqian', 'cwen'] for name in names : if name not in counts: counts[name] = 1 else : counts[name] = counts[name] + 1 print(counts) {'csev': 2, 'zqian': 1, 'cwen': 2}
Η μέθοδος get για λεξικά Αυτή η επαναλαμβανόμενη διαδικασία, να ελέγξουμε εάν ένα κλειδί υπάρχει σε ένα λεξικό και να υποθέσουμε μια προκαθορισμένη τιμή εάν το κλειδί δεν υφίσταται είναι τόσο κοινή, ώστε δημιουργήθηκε μια μέθοδος με το όνομα get(), η οποία το κάνει για εμάς if name in counts: x = counts[name] else : x = 0 x = counts.get(name, 0) Προκαθορισμένη τιμή (ή None) εάν δεν υφίσταται το κλειδί (και όχι σφάλμα) {'csev': 2, 'zqian': 1, 'cwen': 2}
Απλοποιημένη καταμέτρηση με get() Χρησιμοποιούμε την get() και δίδουμε μια προκαθορισμένη τιμή ίση με μηδέν όταν το κλειδί δεν υπάρχει ακόμα στο λεξικό - και μετά απλά προσθέτουμε ένα counts = dict() names = ['csev', 'cwen', 'csev', 'zqian', 'cwen'] for name in names : counts[name] = counts.get(name, 0) + 1 print(counts) Προκαθορισμένη τιμή {'csev': 2, 'zqian': 1, 'cwen': 2}
Επαναλαμβανόμενη διαδικασία καταμέτρησης counts = dict() print('enter a line of text:') line = input('') words = line.split() print('words:', words) print('counting... ') for word in words: counts[word] = counts.get(word,0) + 1 print ('Counts', counts) Η γενική διαδικασία ανάγνωσης των λέξεων σε μια γραμμή κειμένου είναι να σπάσουμε την γραμμή σε λέξεις, να επισκεφτούμε όλες τις λέξεις με βρόγχο και με ένα λεξικό να καταμετρήσουμε το πλήθος των λέξεων για κάθε μία χωριστά.
Καταμέτρηση λέξεων python wordcount.py Enter a line of text: the clown ran after the car and the car ran into the tent and the tent fell down on the clown and the car Words: ['the', 'clown', 'ran', 'after', 'the', 'car', 'and', 'the', 'car', 'ran', 'into', 'the', 'tent', 'and', 'the', 'tent', 'fell', 'down', 'on', 'the', 'clown', 'and', 'the', 'car'] Counting Counts {'and': 3, 'on': 1, 'ran': 2, 'car': 3, 'into': 1, 'after': 1, 'clown': 2, 'down': 1, 'fell': 1, 'the': 7, 'tent': 2}
counts = dict() print('enter a line of text:') line = input('') words = line.split() print('words:', words) print('counting... ') for word in words: counts[word] = counts.get(word,0) + 1 print ('Counts', counts) python wordcount.py Enter a line of text: the clown ran after the car and the car ran into the tent and the tent fell down on the clown and the car Words: ['the', 'clown', 'ran', 'after', 'the', 'car', 'and', 'the', 'car', 'ran', 'into', 'the', 'tent', 'and', 'the', 'tent', 'fell', 'down', 'on', 'the', 'clown', 'and', 'the', 'car'] Counting... Counts {'and': 3, 'on': 1, 'ran': 2, 'car': 3, 'into': 1, 'after': 1, 'clown': 2, 'down': 1, 'fell': 1, 'the': 7, 'tent': 2}
Πεπερασμένοι Βρόγχοι και Λεξικά Αν και τα λεξικά δεν αποθηκεύουν την σειρά των στοιχείων, μπορούμε να γράψουμε ένα βρόγχο for που επισκέπτεται όλες τις εγγραφές σε ένα λεξικό - που στην ουσία επισκέπτεται όλα τα κλειδιά του λεξικού και αναζητεί τις τιμές >>> counts = { 'chuck' : 1, 'fred' : 42, 'jan': 100} >>> for key in counts:... print(key, counts[key])... jan 100 chuck 1 fred 42 >>>
Λαμβάνοντας λίστες με Κλειδιά και Τιμές Μπορούμε να πάρουμε λίστα με τα κλειδιά, τις τιμές, ή πλειάδες (και τα δύο) από ένα λεξικό >>> jjj = { 'chuck' : 1, 'fred' : 42, 'jan': 100} >>> print(list(jjj)) ['jan', 'chuck', 'fred'] >>> print(jjj.keys()) ['jan', 'chuck', 'fred'] >>> print(jjj.values()) [100, 1, 42] >>> print(jjj.items()) [('jan', 100), ('chuck', 1), ('fred', 42)] >>>
Δώρο: Δύο μεταβλητές επανάληψης Επισκεπτόμαστε τα ζεύγη κλειδί-τιμή σε ένα λεξικό με τη χρήση *δύο* μεταβλητών επανάληψης Σε κάθε κύκλο επανάληψης, η πρώτη μεταβλητή είναι το κλειδί και η δεύτερη μεταβολητή είναι η αντίστοιχη τιμή για το κλειδί αυτό >>> jjj = { 'chuck' : 1, 'fred' : 42, 'jan': 100} >>> for aaa,bbb in jjj.items() :... print aaa, bbb... jan 100 chuck 1 fred 42 >>> aaa bbb [jan] 10 0 [chuck] 1 [fred] 42
name = input('enter file:') handle = open(name, 'r') text = handle.read() words = text.split() counts = dict() for word in words: counts[word] = counts.get(word,0) + 1 bigcount = None bigword = None for word,count in counts.items(): if bigcount is None or count > bigcount: bigword = word bigcount = count python words.py Enter file: words.txt t o 16 python words.py Enter file: clown.txt the 7 print(bigword, bigcount)
Αντιστρέφοντας ένα Λεξικό Μερικές φορές θέλουμε να βρούμε το κλειδί που αντιστοιχεί σε μια τιμή Αυτό δεν είναι προφανές να γίνει Αυτό σημαίνει ότι το dict[value] δε θα επιστρέψει το κλειδί Δηλαδή, θέλουμε ένα όμοιο λεξικό με τις τιμές και τα κλειδιά ανεστραμμένα Για ένα νεοδημιούργούμενο λεξικό, μπορούμε να δημιουργήσουμε δύο λεξικά, με το ένα να είναι το αντίστροφο του άλλου Αλλιώς, θα πρέπει να δημιουργήσουμε το ανάστροφο από ένα λεξικό που ήδη υπάρχει
Το πρόβλημα Ενώ τα κλειδιά πρέπει να είναι μοναδικά, για τις τιμές δεν ισχύει αυτός ο περιορισμός Οπότε, πολλά κλειδιά μπορεί να αντιστοιχίζονται στις ίδιες τιμές Πώς φτιάχνουμε το ανεστραμμένο λεξικό; Μπορούμε και πάλι να βαλούμε τις τιμές για κλειδιά, αλλά δε θα έχουμε αρκετές τιμές ώστε να δώσουμε μοναδική τιμή σε κάθε κλειδί Αυτό λύνεται αντιστοιχίζοντας σε κάθε τιμή, μια λίστα κλειδιών που αντιστοιχούν σε αυτή την τιμή στην αρχική λίστα
dct={'thanasis':40,'vagelis':40,'george':35,'ma ry':29} def reverse1(d): ret = dict() for (k,v) in d.items(): if v not in ret: ret[v] = k else: if type(ret[v]) == list: ret[v] = ret[v].append(k) else: lst = [ret[v]] ret[v] = lst ret[v].append(k) return ret print(reverse1(dct)) def reverse2(d): ret = dict() for (k,v) in d.items(): ret[v] = ret.get(v,[]) print(v,ret[v]) ret[v].append(k) return ret print(reverse2(dct)) {40: ['vagelis', 'thanasis'], 35: ['george'], 29: ['mary']} {40: ['vagelis', 'thanasis'], 35: 'george', 29: 'mary'}
Ταξινόμηση Λεξικού Δε διαθέτει τη μέθοδο sort() Όμως, μπορούμε να χρησιμοποιήσουμε την ενσωματωμένη συνάρτηση sorted() Ταξινόμηση των κλειδιών sorted(dct) Ταξινόμηση βάσει τιμών sorted(dct.items(), key=lambda x:x[1]) Ταξινόμηση τιμών/κλειδιών sorted(dct.items())
Σύνοψη Τι είναι μια Συλλογή; Λίστες ή Λεξικά Σταθερές Λεξικών Η πιό συχνή λέξη Χρήση της μεθόδου get() Το hashing και η απουσία σειράς Συντάσσοντας βρόγχους για λεξικά Πρώτη ματιά : Πλειάδες (tuples) Ταξινομώντας Λεξικά