Python - wprowadzenie

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
Last updated on 10 Mar 2021
Published on 10 Mar 2021