TI/Słowniki i zbiory

Z Brain-wiki

W poprzednim rozdziale przedstawione były struktury danych zawierające elementy w pewnym określonym porządku — listy, krotki, napisy. W przypadku struktur danych takich jak słowniki czy zbiory elementy nie mają określonej kolejności. Nie znaczy to, że nie można wykonać operacji dla każdego elementu zbioru jak dla zwykłej sekwencji, tylko że kolejność elementów w zbiorze nie jest dobrze określona.

Słownik

O słowniku wygodnie jest myśleć jako o nieposortowanym zbiorze par klucz:wartość, przy czym klucz musi być unikalny. W słowniku kojarzymy klucze (nazwy) z wartościami (szczegółami). Przykładem słownika jest książka adresowa, w której możesz znaleźć czyjś adres lub telefon znając dane tej osoby.

Kluczem może być tylko obiekt niezmienny (na przykład napis czy krotka), ale wartości mogą być dowolne (napisy, krotki, listy, słowniki, liczby, ...). Tutaj niezmienność krotek znajduje swoje zastosowanie.

Do tworzenia słowników służy następująca notacja:

s = {klucz1 : wartość1, klucz2 : wartość2}

Między kluczem a wartością jest dwukropek, zaś między parami są przecinki. Wszystko jest zamknięte w nawiasach klamrowych.

Pamiętaj, że klucze w słowniku nie są w żaden sposób posegregowane. Jeżeli chcesz mieć je poukładane w jakimś szczególnym porządku, musisz ich listę samemu posortować.

Słowniki to po angielsku dictionary, zaś klasa nazywa się krótko dict.

Wyjaśnienie dla matematyka

Słownik to funkcja w sensie matematycznym — ze zbioru kluczy w i na zbiór wartości.


Przykład:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Nazwa pliku: slownik.py

# "ka" to skrót od "k"siążka "a"dresowa

ka = { 'Jan'   : 'jasiek@jasiowo.pl',
       'Tomek' : 'tomek@cba.gov',
       'Ela'   : 'ela@zzzz.com',
       'Kasia' : 'katarzyna@hopla.us'
    }

print "Adres Kasi:", ka['Kasia']

# Usuwanie pary klucz-wartość.
del ka['Kasia']

print u'\nKontaktów w książce adresowej jest {0}.\n'.format(len(ka))
# iterowanie przez pary słownika
for imie, adres in ka.items():
    print '{0} ma adres {1}'.format(imie, adres)

# Dodawanie pary klucz-wartość.
ka['Wojtek'] = 'wojtas@kumple.pl'

if 'Wojtek' in ka:
    print "\nAdres Wojtka:", ka['Wojtek']

# pobranie listy kluczy w słowniku
l = ka.keys()
print l

# sprawdzenie czy klucz jest w słowniku
jest =  'Tomek' in ka
print jest
Rezultat:
Adres Kasi: katarzyna@hopla.us

Kontaktów w książce adresowej jest 3.

Jan ma adres jasiek@jasiowo.pl
Ela ma adres ela@zzzz.com
Tomek ma adres tomek@cba.gov

Adres Wojtka: wojtas@kumple.pl
['Jan', 'Wojtek', 'Ela', 'Tomek']
True

Jak to działa?

Tworzymy słownik ka używając omówionej już wcześniej notacji. Następnie docieramy do jednej z wartości używając nazwiska jako klucza. Operację pobrania elementu zapisujemy podobnie jak w przypadku indeksowania sekwencji. Niemniej pary w słowniku nie są uporządkowane i jako „indeksu” do słownika można użyć tylko jeden z kluczy.

Możemy usuwać wpisy ze słownika za pomocą polecenia del — po prostu określamy słownik i klucz, który razem z odpowiednią wartością ma zostać usunięty. Samej wartości nie musimy wcale znać przy tej operacji.

Następnie używamy metody items, która zwraca nam pary w postaci krotek, z których każda składa się z dwóch elementów — pierwszy to klucz, a drugi to wartość. Dzięki for...in... przypisujemy te pary do zmiennych, odpowiednio imie i adres, po czym wypisujemy je w bloku for. Do formatowania napisu wykorzystujemy tu metodę format. Jej argumentem jest krotka. Za numery w nawiasach klamrowych metoda format podstawia element krotki o tym indeksie. Możemy dodać nową parę klucz-wartość po prostu używając operatora indeksowania do oznaczenia klucza i przypisania mu wartości, tak jak zrobiliśmy to dla Wojtka w powyższym przykładzie.

Możemy sprawdzić czy dany klucz istnieje w słowniku za pomocą operatora in.

Jeśli chcesz poznać wszystkie metody dostępne dla klasy słowników, wpisz help(dict) albo zajrzyj do pomocy na sieci.

Słowniki i krotki w przekazywaniu argumentów w wywołaniu funkcji

Tak jak zostało to wcześniej wspomniane, słowniki służą do przekazywania nadmiarowych argumentów nazwanych do funkcji. Jako klucze słownika zostają użyte nazwy (nieistniejących) parametrów w postaci napisów. Klucze wskazują z kolei na wartości argumentów.

Przykład

def wypisz(separator,*wyrazy, **dodatkowe_informacje):
    print separator # ten argument MUSI wystąpić w wywołaniu funkcji
    print wyrazy    # krotka zawierająca dodatkowe, NIENAZWANE argumenty 
    print dodatkowe_informacje # słownik zawierający dodatkowe NAZWANE argumenty
    
    for w in wyrazy:
        print w, separator,
    print 
    for klucz,wartosc in dodatkowe_informacje.items():
        print klucz, wartosc 


wypisz(';', 'Być','albo' ,'nie być', sztuka='Hamlet', autor='Szekspir')
Rezultat
;
('By\xc4\x87', 'albo', 'nie by\xc4\x87')
{'sztuka': 'Hamlet', 'autor': 'Szekspir'}
Być ; albo ; nie być ;
sztuka Hamlet
autor Szekspir


Dodatkowe zadania i przykłady

Zob. też bardziej zaawansowane przykłady w rozdziale o wyjątkach.

Bardziej ambitne zadanie wymagające inteligentnego użycia słowników: anagramy.

Zbiór

Zbiory to nieuporządkowane zestawy prostych obiektów. Używamy ich, gdy istotny jest tylko fakt występowania elementu, a nie jego położenie albo liczba powtórzeń.

Zbiory możesz testować pod kątem występowania danego elementu, sprawdzać czy to jest podzbiór innego zbioru, szukać części wspólnej zbiorów i tak dalej.

Przykład:
>>> kraje = set(['Brazylia', 'Rosja', 'Indie'])
>>> kraje.__contains__('Indie')
True
>>> kraje.__contains__('USA')
False
>>> kraje2 = kraje.copy()
>>> kraje2.add('Chiny')   
>>> kraje2.issuperset(kraje) 
True
>>> kraje.issubset(kraje2)
True
>>> kraje.remove('Rosja')
>>> kraje.intersection(kraje2)
set(['Brazylia', 'Indie'])

Lista operatorów działających na zbiory jest przedstawiona w tabeli operatorów w drugim rozdziale.

Te same operacje co powyżej można zwięźlej zapisać korzystając z operatorów zamiast metod.

>>> kraje = set(['Brazylia', 'Rosja', 'Indie'])
>>> 'Indie' in kraje
True
>>> 'USA' in kraje
False
>>> kraje2 = kraje | set(['Chiny'])
>>> kraje2 > kraje
True
>>> kraje < kraje2
True
>>> kraje.remove('Rosja')
>>> kraje & kraje2
set(['Brazylia', 'Indie'])


Wyjaśnienie dla matematyka

Zbiór — struktura danych języka Python — posiada własności i można na nim wykonywać operacje takie jak dla zbioru w sensie obiektu matematycznego.


Jak to działa?

Ten przykład nie wymaga omawiania, gdyż użyte w nim są jedynie proste techniki matematyczne uczone w szkole. Dla porządku dodamy znaczenie używanych tu słów z języka angielskiego: set — zbiór, superset — nadzbiór, subset — podzbiór, intersection — część wspólna zbiorów.

Podsumowanie

Przestudiowaliśmy dokładnie różne wbudowane struktury danych Pythona. Będą one niezbędne przy pisaniu programów bardziej złożonych programów.