Zadanie
Napisz funkcję def transform(matrix)
, która przekształci naszą macierz matrix = [[1,2,3],[4,5,6],[7,8,9]]
w listę składającą się z jej połączonych kolumn [1, 4, 7, 2, 5, 8, 3, 6, 9]
.
Nasza macierz
Nasza macierz to tak naprawdę tablica dwuwymiarowa. W Pythonie taką strukturę tworzy się jako listę list. Oto jak wygląda nasz matrix i jak indeksy określają jej poszczególne pola.
Jaki jest nasz cel ?
Musimy napisać funkcję, która przekształci naszą tablicę dwuwymiarową w pożądany sposób. Oto jak poszczególne elementy macierzy mają zostać odwzorowane w liście.
Rozwiązanie
matrix = [[1,2,3],[4,5,6],[7,8,9]] def transform(matrix): l = [] for numer_kolumny in range(len(matrix[0])): for numer_wiersza in range(len(matrix)): l.append(matrix[numer_wiersza][numer_kolumny]) return l print(transform(matrix))
Output:
[1, 4, 7, 2, 5, 8, 3, 6, 9]
Szybko poszło. I nawet działa. Można by powiedzieć, że zadanie zostało rozwiązane. Ja osobiście pochwalam takie podejście. Kandydat dostaje zadanie i rozwiązuje je w najprostszy sposób by zyskać na czasie. Sam robię tak samo. W ten sposób zawsze masz już pod ręka coś co już działa. Nie zawsze jest czas by szukać bardziej optymalnych rozwiązań. Dzisiaj jednak postarajmy się troszkę ”stuningować” nasz kod.
Zip
Nasza macierz to lista list. By przygotować naszą listę musimy pobrać dane jednocześnie ze wszystkich list będących wierszami. Do jednoczesnego iterowania się po wielu listach służy funkcja zip.
Przykład użycia
>>> lista1 = [1, 2, 3] >>> lista2 = [4, 5, 6] >>> list(zip(lista1, lista2)) [(1, 4), (2, 5), (3, 6)]
Zatem bez problemu możemy połączyć nasze listy w dowolny sposób. Zauważ, że funkcja zip może przyjąć dowolną liczbę list jako kolejne parametry. W naszym przypadku funkcja zip moglaby przyjąć wszystkie listy będące wierszami naszej macierzy. list(zip(matrix[0],matrix[1],matrix[2]))
Takie rozwiązanie jest mało przenośne. Działałoby bowiem tylko dla macierzy o 3 wierszach. Jak zatem zapewnić przenośność naszego rozwiązania ? Użyjemy operatora * by wypakować wszystkie listy (wiersze) i w ten sposób przekazać je do funkcji zip list(zip(*matrix))
. Kod wygląda teraz tak:
matrix = [[1,2,3],[4,5,6],[7,8,9]] def transform(matrix): lista = [] for kolumna in list(zip(*matrix)): for wartosc in kolumna: lista.append(wartosc) return lista print(transform(matrix))
Output:
[1, 4, 7, 2, 5, 8, 3, 6, 9]
No i udało się. Pozbyliśmy się brzydkiego pobierania po indeksach. Dodatkowo nie musimy już używać funkcji ”range” by sztucznie tworzyć numery indeksów. Zamiast to mamy piękne pętle iterujące się po listach. To jednak nie koniec poprawek.
Lista składana
Nie był bym sobą gdybym nie zaproponował tego rozwiązania. Nasz przykład aż się o nie prosi. Zatem przeróbmy nasze poprzednie rozwiązanie na listę składną:
matrix = [[1,2,3],[4,5,6],[7,8,9]] def transform(matrix): return [ wartosc for kolumna in list(zip(*matrix)) for wartosc in kolumna ] print(transform(matrix))
Output:
[1, 4, 7, 2, 5, 8, 3, 6, 9]
Można powiedzieć, że udało nam się rozwiązać to zadanie w jednej linii. Ja jednak jestem fanem zapisywania list składanych w wielu liniach, tak aby poprawić ich czytelność. Nie jest to jednak wymagane. Tak czy inaczej świetna robota. Nasz kod jest teraz o wiele bardziej ”Pythonic”.