02 - Listy składane (`list comprehension`)
Dotychczas, chcąc wypełnić listę zestawem kolejnych liczb, używaliśmy takiego kodu:
liczby = list(range(1,10))
print(liczby)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Listę liczb parzystych uzyskiwaliśmy np. tak:
liczby = []
for i in range(1,10):
if i % 2 == 0:
liczby.append(i)
print(liczby)
[2, 4, 6, 8]
Oczywiście można by to samo uzyskać w ten sposób:
liczby = list(range(2,10, 2))
print(liczby)
ale dla celów dydaktycznych będziemy się trzymać poprzedniej składni.
Chcąc stworzyć listę składająca się z kolejnych parzystych liczb, podniesionych do potęgi moglibyśmy napisać tak:
liczby = []
for i in range(1,10):
if i % 2 == 0:
liczby.append(i**2)
print(liczby)
[4, 16, 36, 64]
Taki kod dobrze się sprawdza, ale można go napisać krócej. Np. listę liczb parzystych uzyskamy używając kodu:
liczby = [i for i in range(1, 10) if i % 2 == 0]
print(liczby)
[2, 4, 6, 8]
Natomiast listę liczb parzystych podniesionych do kwadratu również można otrzymać, używając tak ,,skondensowanego’’ kodu:
liczby = [i**2 for i in range(1, 10) if i % 2 == 0]
print(liczby)
[4, 16, 36, 64]
Jak widać, to co wcześniej zajmowało cztery linie kodu, teraz można osiągnąć, używając jednej. Zastosowaliśmy właśnie listę składaną.
Można kod dalej rozbudowywać:
liczby = [i for i in range(1, 20) if i % 2 == 0 if i % 3 == 0]
print(liczby)
[6, 12, 18]
Także zastosować konstrukcję if ... else
:
sekwencja = 'ACCGTA'
zasady = ['puryna' if z == 'A' or z == 'G' else 'pirymidyna' for z in sekwencja]
print(zasady)
['puryna', 'pirymidyna', 'pirymidyna', 'puryna', 'pirymidyna', 'puryna']
Poza wyrażeniami arytmetycznymi można też na generowanych elementach wywoływać funkcje, czy metody:
sekwencja = 'ACCGTA'
sekwencja_male = [z.lower() for z in sekwencja]
print(sekwencja_male)
['a', 'c', 'c', 'g', 't', 'a']
Listy składane mogą się przydać przy tworzeniu nieco bardziej złożonych struktur danych, tu listy krotek:
wartosci = [22, 12, 21, 18, 15, 13, 18]
obiekty = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
dane = [(o, w) for o, w in zip(obiekty, wartosci)]
print(dane)
[('A', 22), ('B', 12), ('C', 21), ('D', 18), ('E', 15), ('F', 13), ('G', 18)]
Teraz użyjmy nieco bardziej złożonego przykładu. Przypuśćmy, że mamy jedną listę dłuższych sekwencji (dlugie
), oraz drugą, zawierającą krótsze sekwencje. Chcemy wyszukać wszystkie krótsze sekwencje we wszystkich dłuższych a rezultat tych porównań zachować w liście, zawierającej krótsze listy, które będą zawierać obie porównywane sekwencje i wynik porównania (True
lub False
). Używając ,,klasycznej’’ zagnieżdżonej konstrukcji for
, można to zrobić tak:
dlugie = ['AGACAAGAA', 'TTTCAAGGG', 'GGAGACCTA', 'AAGGTTAAA']
krotkie = ['AGA', 'AGG']
wynik = []
for d in dlugie:
for k in krotkie:
wynik.append([d, k, k in d])
print(f'Lista: {wynik}')
#Estetyczny wydruk:
print()
for k, d, t in wynik:
print(f'{k} {d} {t}')
Lista: [['AGACAAGAA', 'AGA', True], ['AGACAAGAA', 'AGG', False], ['TTTCAAGGG', 'AGA', False], ['TTTCAAGGG', 'AGG', True], ['GGAGACCTA', 'AGA', True], ['GGAGACCTA', 'AGG', False], ['AAGGTTAAA', 'AGA', False], ['AAGGTTAAA', 'AGG', True]]
AGACAAGAA AGA True
AGACAAGAA AGG False
TTTCAAGGG AGA False
TTTCAAGGG AGG True
GGAGACCTA AGA True
GGAGACCTA AGG False
AAGGTTAAA AGA False
AAGGTTAAA AGG True
Zastosujmy teraz listę składaną:
dlugie = ['AGACAAGAA', 'TTTCAAGGG', 'GGAGACCTA', 'AAGGTTAAA']
krotkie = ['AGA', 'AGG']
wynik = [[d, k, k in d] for d in dlugie for k in krotkie]
print(wynik)
#Estetyczny wydruk:
print()
for k, d, t in wynik:
print(f'{k} {d} {t}')
[['AGACAAGAA', 'AGA', True], ['AGACAAGAA', 'AGG', False], ['TTTCAAGGG', 'AGA', False], ['TTTCAAGGG', 'AGG', True], ['GGAGACCTA', 'AGA', True], ['GGAGACCTA', 'AGG', False], ['AAGGTTAAA', 'AGA', False], ['AAGGTTAAA', 'AGG', True]]
AGACAAGAA AGA True
AGACAAGAA AGG False
TTTCAAGGG AGA False
TTTCAAGGG AGG True
GGAGACCTA AGA True
GGAGACCTA AGG False
AAGGTTAAA AGA False
AAGGTTAAA AGG True
Zadania
Zadanie 1
Napisz program, który sprawdzi, czy w długiej sekwencji (np. AAAAAGGAATTCCCCTAGAATTAAAAACCAGGTTACTG
) znajdują się trójzasadowe odcinki, np: AAA
, ATT
, GGG
, AGG
.
Rozwiązanie
sekwencja = 'AAAAAGGAATTCCCCTAGAATTAAAAACCAGGTTACTG'
odcinki = ['AAA', 'ATT', 'GGG', 'AGG']
wynik = [[o, o in sekwencja] for o in odcinki]
for s, t in wynik:
print(f'{s}: {t}')
AAA: True
ATT: True
GGG: False
AGG: True
Zadanie 2
Zmodyfikuj program tak, aby drukował znalezione fragmenty (!), wraz z ich pozycjami w długiej sekwencji.
import re
sekwencja = 'AAAAAGGAATTCCCCTAGAATTAAAAACCAGGTTACTG'
odcinki = ['AAA', 'ATT', 'GGG', 'AGG']
wynik = [[o, w.start()] for o in odcinki for w in re.finditer(o, sekwencja) ]
for s, m in wynik:
print(f'{s}: {m}')
AAA: 0
AAA: 22
ATT: 8
ATT: 19
AGG: 4
AGG: 29