Zadanie
Podany jest następujący słownik będący zapisem logów pewnego programu.
nasz_slownik = { 20: 'ERROR', 33: 'WARNING', 59: 'WARNING4', 74: 'ERROR', 99: 'ERROR', 81: 'WARNING', 62: 'INFO', 84: 'ERROR', 36: 'WARNING', 46: 'WARNING2', 85: 'ERROR', 64: 'INFO', 71: 'ERROR1', 7: 'ERROR', 37: 'INFO4', 90: 'INFO', 13: 'INFO', 93: 'INFO', 68: 'ERROR', 47: 'WARNING' }
Kluczem jest znacznik czasowy, natomiast wartością typ logu jaki o danym czasie został zarejestrowany w systemie. Naszym zadaniem jest napisanie funkcji, która pobierze wszystkie różne typy eventów/logów jakie pojawiły się w danym przedziale czasu.
Nagłówek funkcji będzie wyglądać następująco:
def pobierz_logi(poczatek_przedzialu, koniec_przedzialu,nasz_slownik):
Informacje dodatkowe
- Jak widzisz naszymi kluczami są wartości całkowite (int). W oryginalnym przykładzie były to timestumpy, lecz na potrzeby uproszczenia zadania zamieniłem to na int.
- Nasza mapa nie jest posortowana
Rozwiązanie
Za każdym razem jeśli masz za zadanie pobranie tylko różnych elementów z listy lub jakiejś innej kolekcji należy rozważyć użycie typu danych set. Załatwia on za nas eliminacje powtarzających się elementów.
moj_set = set() moj_set.add('ERROR') moj_set.add('ERROR') moj_set.add('ERROR') moj_set.add('INFO') moj_set.add('INFO') print(moj_set)
Output:
{'ERROR', 'INFO'}
Mimo wielokrotnego dodawania kolejnych wartości „ERROR” i „INFO” występują one w naszej kolekcji tylko raz. W takim wypadku jedyne co musimy zrobić to umieścić nasze logi z odpowiedniego przedziału w kolekcji set i sam set zrobi już za nas całą robotę.
Zadanie to celowo rozwiążemy na dwa sposoby używając:
- Pętli for
- List składanych
Listy składane często sprawiają wiele problemów początkującym, jednak jest na nie sposób. Zachęcam do napisania zwykłej pętli for, a następnie przetworzenia jej na listę składaną. Takie podejście znacznie ułatwia sprawę.
Sposób z użyciem pętli for
nasz_slownik = { 20: 'ERROR', 33: 'WARNING', 59: 'WARNING4', 74: 'ERROR', 99: 'ERROR', 81: 'WARNING', 62: 'INFO', 84: 'ERROR', 36: 'WARNING', 46: 'WARNING2', 85: 'ERROR', 64: 'INFO', 71: 'ERROR1', 7: 'ERROR', 37: 'INFO4', 90: 'INFO', 13: 'INFO', 93: 'INFO', 68: 'ERROR', 47: 'WARNING' } def pobierz_logi(poczatek_przedzialu, koniec_przedzialu,nasz_slownik): nasz_set = set() for key, value in nasz_slownik.items(): if key > poczatek_przedzialu and key < koniec_przedzialu: nasz_set.add(value) return nasz_set print(pobierz_logi(13, 60, nasz_slownik))
Teraz przerobimy to na zbiór składany (set comprehension).
Sposób z użyciem zbioru składanego
nasza_slownik = { 20: 'ERROR', 33: 'WARNING', 59: 'WARNING4', 74: 'ERROR', 99: 'ERROR', 81: 'WARNING', 62: 'INFO', 84: 'ERROR', 36: 'WARNING', 46: 'WARNING2', 85: 'ERROR', 64: 'INFO', 71: 'ERROR1', 7: 'ERROR', 37: 'INFO4', 90: 'INFO', 13: 'INFO', 93: 'INFO', 68: 'ERROR', 47: 'WARNING' } def pobierz_logi(poczatek_przedzialu, koniec_przedzialu,nasz_slownik): return { value #to co wcześniej znajdowało się w apned for key, value in nasza_mapa.items() # ta sama pętla co w poprzednim przykładzie if key > poczatek_przedzialu and key < koniec_przedzialu # ten sam warunek co w poprzednim przykładzie } print(pobierz_logi(13, 60, nasz_slownik))
Moim zdaniem drugi wariant jest o wiele czytelniejszy. Nie wymaga też tworzenia tymczasowej kolekcji set. Pewnie już nie raz spotkałeś się z listą składaną zapisaną w jednej linijce. Nasze rozwiązanie również można by było zapisać w jednej linii. Jednak linia ta była by bardzo długo co obniżyło by czytelność kodu i z pewnością nie przeszło sprawdzania PEP8. Sam język nie wymusza stosowania nowych linii pozwala za to na łamanie ich gdzie będzie ci wygodnie. Żadne wcięcia, czy tabulacje nie są tu wymagane. Tyle na dzisiaj. Miłej zabawy z listami składanymi. Polecam zapisywać je w więcej niż jednej linii.
Świetne wytłumaczenie list składanych. Dzięki 🙂