# Μητρωα

Το κεφάλαιο αυτό αναφέρεται στα μητρώα (dictionaries). Τα μητρώα έχουν κλειδιά (keys) και τιμές (values). Τα κλειδιά χρησιμοποιούνται για να βρίσκουμε τις τιμές. Να ένα παράδειγμα ενός μητρωου σε χρήση:

    def print_menu():
        print '1. Print Phone Numbers'
        print '2. Add a Phone Number'
        print '3. Remove a Phone Number'
        print '4. Lookup a Phone Number'
        print '5. Quit'
        print
    numbers = {}
    menu_choice = 0
    print_menu()
    while menu_choice != 5:
        menu_choice = input("Type in a number (1-5):")
        if menu_choice == 1:
            print "Telephone Numbers:"
            for x in numbers.keys():
                print "Name: ",x," \tNumber: ",numbers[x]
            print
        elif menu_choice == 2:
            print "Add Name and Number"
            name = raw_input("Name:")
            phone = raw_input("Number:")
            numbers[name] = phone
        elif menu_choice == 3:
            print "Remove Name and Number"
            name = raw_input("Name:")
            if numbers.has_key(name):
                del numbers[name]
            else:
                print name," was not found"
        elif menu_choice == 4:
            print "Lookup Number"
            name = raw_input("Name:")
            if numbers.has_key(name):
                print "The number is",numbers[name]
            else:
                print name," was not found"
        elif menu_choice != 5:
            print_menu()

Και το αποτέλεσμά μου:

    1. Print Phone Numbers
    2. Add a Phone Number
    3. Remove a Phone Number
    4. Lookup a Phone Number
    5. Quit

    Type in a number (1-5):2
    Add Name and Number
    Name:Joe
    Number:545-4464
    Type in a number (1-5):2
    Add Name and Number
    Name:Jill
    Number:979-4654
    Type in a number (1-5):2
    Add Name and Number
    Name:Fred
    Number:132-9874
    Type in a number (1-5):1
    Telephone Numbers:
    Name:  Jill     Number:  979-4654
    Name:  Joe      Number:  545-4464
    Name:  Fred     Number:  132-9874

    Type in a number (1-5):4
    Lookup Number
    Name:Joe
    The number is 545-4464
    Type in a number (1-5):3
    Remove Name and Number
    Name:Fred
    Type in a number (1-5):1
    Telephone Numbers:
    Name:  Jill     Number:  979-4654
    Name:  Joe      Number:  545-4464

    Type in a number (1-5):5

Το πρόγραμμα είναι παρόμοιο με τον καταλογου ονομάτων που είδαμε στο κεφάλαιο για τους καταλογους. Να πως λειτουργεί. Πρώτα ορίζεται η συνάρτηση `print_menu`. Η `print_menu` απλώς εμφανίζει ένα μενού που αργότερα χρησιμοποιείται δυο φορές μέσα στο πρόγραμμα. Ακολουθεί η περίεργη γραμμή `numbers = {}`. Αυτό που κάνει η γραμμή αυτή είναι να ενημερώσει την Python ότι το `numbers` είναι ένα μητρώο. Οι επόμενες γραμμές κάνουν το μενού λειτουργικό. Οι γραμμές:

    for x in numbers.keys():
        print "Name: ",x," \tNumber: ",numbers[x]

``διατρέχουν'' το μητρώο και εμφανίζουν όλες τις πληροφορίες. Η συνάρτηση `numbers.keys()` επιστρέφει έναν καταλογο που χρησιμοποιείται από τον βρόγχο `for`. Ο κατάλογος που επιστρέφεται από την `keys` δεν έρχεται ταξινομημένη με κάποιο τρόπο. Αν λοιπόν θέλετε τα στοιχεία με κάποια σειρά θα πρέπει να ταξινομηθούν. Όπως και με τους καταλογους η δήλωση `numbers[x]` χρησιμοποιείται για να μας δώσει πρόσβαση σε ένα συγκεκριμένο στοιχείο του μητρώου. Φυσικά στην περίπτωσή αυτή το `x` είναι κείμενο. Έπειτα η γραμμή `numbers[name] = phone` προσθέτει ένα όνομα και αριθμό τηλεφώνου στο μητρώο. Αν το όνομα `name` υπάρχει ήδη στο μητρώο το τηλέφωνο `phone` θα αντικαταστήσει ότιδήποτε υπήρχε προηγουμένως. έπειτα είναι οι γραμμές:

    if numbers.has_key(name):
        del numbers[name]

που ελέγχουν αν ένα όνομα βρίσκεται στο μητρώο και το διαγράφουν αν όντως υπάρχει. Η συνάρτηση `numbers.has_key(name)` είναι αληθής αν η `name` βρίσκεται στο `numbers` και ψευδής σε κάθε άλλη περίπτωση. Η γραμμή `del numbers[name]` αφαιρεί το κλειδί `name` και την συσχετιζόμενη με το κλειδί τιμή. Οι γραμμές:

    if numbers.has_key(name):
        print "The number is",numbers[name]

ελέγχουν αν το μητρώο έχει ένα συγκεκριμένο κλειδί και αν όντως το έχει εμφανίζεται ο ραιθμός που σχετίζεται με αυτό το κλειδί. Τέλος αν η επιλογή του χρήστη από το μενού είναι λανθασμένη το μενού εμφανίζεται ξανά προς τέρψιν οφθαλμών...

Ανακεφαλαίωση: Τα μητρώα έχουν κλειδία και τιμές. Τα κλειδιά μπορεί να είναι κείμενο ή αριθμοί. Τα κλειδιά αναφέρονται σε τιμές. Οι τιμές μπορούν να είναι κάθε τύπος μεταβλητής ακόμα και καταλογοι ή μητρώα (και αυτοι οι κατάλογοι και τα μητρώα πάλι μπορούν να περιέχουν άλλους καταλογους κι άλλα μητρώα (δεν είναι τρομαχτικό;)). Να ένα παράδειγμα ενός μητρώου που περιέχει έναν καταλογο:

    max_points = [25,25,50,25,100]
    assignments = ['hw ch 1','hw ch 2','quiz   ','hw ch 3','test']
    students = {'#Max':max_points}

    def print_menu():
        print "1. Add student"
        print "2. Remove student"
        print "3. Print grades"
        print "4. Record grade"
        print "5. Print Menu"
        print "6. Exit"

    def print_all_grades():
            print '\t',
            for i in range(len(assignments)):
                print assignments[i],'\t',
            print
            keys = students.keys()
            keys.sort()
            for x in keys:
                print x,'\t',
                grades = students[x]
                print_grades(grades)

    def print_grades(grades):
        for i in range(len(grades)):
            print grades[i],'\t\t',
        print

    print_menu()
    menu_choice = 0
    while menu_choice != 6:
        print
        menu_choice = input("Menu Choice (1-6):")
        if menu_choice == 1:
            name = raw_input("Student to add:")
            students[name] = [0]*len(max_points)
        elif menu_choice == 2:
            name = raw_input("Student to remove:")
            if students.has_key(name):
                del students[name]
            else:
                print "Student: ",name," not found"
        elif menu_choice == 3:
            print_all_grades()

        elif menu_choice == 4:
            print "Record Grade"
            name = raw_input("Student:")
            if students.has_key(name):
                grades = students[name]
                print "Type in the number of the grade to record"
                print "Type a 0 (zero) to exit"
                for i in range(len(assignments)):
                    print i+1,' ',assignments[i],'\t',
                print
                print_grades(grades)
                which = 1234
                while which != -1:
                    which = input("Change which Grade:")
                    which = which-1
                    if 0 <= which < len(grades):
                        grade = input("Grade:")
                        grades[which] = grade
                    elif which != -1:
                        print "Invalid Grade Number"
            else:
                print "Student not found"
        elif menu_choice != 6:
            print_menu()

και η δοκιμαστική εκτέλεση:

    1. Add student
    2. Remove student
    3. Print grades
    4. Record grade
    5. Print Menu
    6. Exit

    Menu Choice (1-6):3
            hw ch 1         hw ch 2         quiz            hw ch 3         test
    #Max    25              25              50              25              100

    Menu Choice (1-6):6
    1. Add student
    2. Remove student
    3. Print grades
    4. Record grade
    5. Print Menu
    6. Exit

    Menu Choice (1-6):1
    Student to add:Bill

    Menu Choice (1-6):4
    Record Grade
    Student:Bill
    Type in the number of the grade to record
    Type a 0 (zero) to exit
    1   hw ch 1     2   hw ch 2     3   quiz        4   hw ch 3     5   test
    0               0               0               0               0
    Change which Grade:1
    Grade:25
    Change which Grade:2
    Grade:24
    Change which Grade:3
    Grade:45
    Change which Grade:4
    Grade:23
    Change which Grade:5
    Grade:95
    Change which Grade:0

    Menu Choice (1-6):3
            hw ch 1         hw ch 2         quiz            hw ch 3         test
    #Max    25              25              50              25              100
    Bill    25              24              45              23              95

    Menu Choice (1-6):6

Πως λειτουργεί το πρόγραμμα; Βασικά η μεταβλητή `students` είναι ένα μητρώο που ως κλειδιά έχει τα ονόματα των σπουδαστών και με τιμές που είναι οι βαθμοί τους. Οι πρώτες δυο γραμμές δημιουργούν δυο καταλογους. Η επόμενη γραμμή `students = {'#Max':max_points}` δημιουργεί ένα νέο μητρώο με κλειδί `#Max` και ορίζει την τιμή σε `[25,25,50,25,100]` (αφού αυτό ήταν το `max_points` όταν έγινε η αντιστοίχιση) (Χρησιμοποιώ το κλειδί `#Max` αφού το σύμβολο `#` ταξινομείται μπροστά από κάθε αλφαβητικό χαρακτήρα). Ύστερα ορίζεται η `print_menu`. Ακολουθεί η συνάρτηση `print_all_grades` με τις γραμμές:

    def print_all_grades():
            print '\t',
            for i in range(len(assignments)):
                print assignments[i],'\t',
            print
            keys = students.keys()
            keys.sort()
            for x in keys:
                print x,'\t',
                grades = students[x]
                print_grades(grades)

Προσέξτε πως τα δυο πρώτα κλειδιά διαγράφηκαν από το μητρώο `students` με την συνάρτηση `keys` στην γραμμή `keys = students.keys()` . Η `keys` είναι ενας κατάλογος και έτσι όλες οι συναρτήσεις για καταλογους μπορούν να εφαρμοστούν σ' αυτήν. Ύστερα τα κλειδιά ταξινομούνται στην γραμμή `keys.sort()` αφού είναι ένας κατάλογος. Ο βρόγχος `for` ``διατρέχει'' όλα τα κλειδιά. Οι βαθμοί φυλάσονται σε έναν καταλογο μέσα στο μητρώο έτσι ώστε ο συσχετισμός `grades = students[x]` να δίνει στη `grades` τον καταλογο που αποθηκεύεται στο κλειδί `x`. Η συνάρτηση `print_grades` απλώς εμφανίζει τον κατάλογο και ορίζεται μερικές γραμμές πιο κάτω.

Οι παρακάτω γραμμές ορίζουν τις διάφορες λειτουργίες του μενού. Η γραμμή `students[name] = [0]*len(max_points)` προσθέτει έναν νέο σπουδαστή στο κλειδί με το όνομά του. Η σημείωση `[0]*len(max_points)` δημιουργεί έναν πίνακα από μηδενικά που έχει το ίδιο μήκος με τον κατάλογο `max_points`.

Η εντολή remove student στο μενού διαγράφει έναν σπουδαστή όπως στο παράδειγμα των αριθμών τηλεφώνου. Η επιλογή record grades είναι λίγο πιο περίπλοκη. Οι βαθμοί ανασύρονται με την γραμμή`grades = students[name]` gets a reference to the grades of the student `name`. Ο βαθμός μετά καταγράφεται με την γραμμή `grades[which] = grade`. Μπορεί να παρατηρήσατε πως η `grades` δεν γυρίζουν ποτέ στο μητρώο των σπουδαστών (as in no `students[name] = grades`). Ο λόγος που δεν υπάρχει τέτοια εντολή είναι ότι η `grades` είναι στην πραγματικότητα ένα άλλο όνομα για τη `students[name]` οπότε αν αλλάζαμε την `grades` θα αλλάζαμε στην ουσία την `student[name]`.

Τα μητρώα παρέχουν έναν εύκολο τρόπο να συνδέουμε κλειδία με τιμές. Έτσι μπορούμε να ανιχνέυουμε δεδομένα που είναι ``εξαρτημένα'' από διάφορα κλειδιά.