Používanie notácie zoznamov jazyka Python

obchodné

V jazyku Python je pri generovaní nového zoznamu jednoduché použiť notáciu zoznam comprehensions.(List comprehensions)

V tomto článku sa budeme najprv zaoberať nasledujúcimi otázkami

  • Základný typ zápisu porozumenia zoznamu
  • Zápis porozumenia zoznamu s podmieneným vetvením pomocou if
  • Kombinácia s ternárnymi operátormi (spracovanie typu if else)
  • zip(),enumerate()Kombinácia s týmito
  • zápis vnoreného zoznamu

Ďalej si vysvetlíme množinu zápisov pre porozumenie zoznamov pomocou vzorového kódu.

  • notácia zahrnutia množiny(Set comprehensions)
  • slovníková inklúzia(Dict comprehensions)
  • typ generátora(Generator expressions)

Základný typ zápisu porozumenia zoznamu

Zápis pre porozumenie zoznamu sa zapisuje takto.

[Expression for Any Variable Name in Iterable Object]

Vezme každý prvok iterovateľného objektu, ako je zoznam, tuple alebo rozsah, podľa ľubovoľného mena premennej a vyhodnotí ho pomocou výrazu. Vráti sa nový zoznam s výsledkom vyhodnotenia ako prvkom.

Príklad je uvedený spolu s ekvivalentným príkazom for.

squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]
squares = []
for i in range(5):
    squares.append(i**2)

print(squares)
# [0, 1, 4, 9, 16]

Rovnaký postup sa dá vykonať aj pomocou funkcie map(), ale pre jednoduchosť a prehľadnosť sa uprednostňuje zápis s porozumením zoznamu.

Zápis porozumenia zoznamu s podmieneným vetvením pomocou if

Možné je aj podmienené vetvenie pomocou if. Napíšte if v postfixe takto.

[Expression for Any Variable Name in Iterable Object if Conditional Expression]

Výrazom sa vyhodnotia len tie prvky iterovateľného objektu, ktorých podmienený výraz je true, a vráti sa nový zoznam, ktorého prvky sú výsledkom.

V podmienenom výraze môžete použiť ľubovoľný názov premennej.

Príklad je uvedený spolu s ekvivalentným príkazom for.

odds = [i for i in range(10) if i % 2 == 1]
print(odds)
# [1, 3, 5, 7, 9]
odds = []
for i in range(10):
    if i % 2 == 1:
        odds.append(i)

print(odds)
# [1, 3, 5, 7, 9]

Rovnaký postup možno vykonať aj pomocou funkcie filter(), ale pre jednoduchosť a prehľadnosť sa uprednostňuje zápis s porozumením zoznamu.

Kombinácia s ternárnymi operátormi (spracovanie typu if else)

V uvedenom príklade sa spracujú len tie prvky, ktoré spĺňajú kritériá, a tie, ktoré kritériá nespĺňajú, sa z nového zoznamu vylúčia.

Ak chcete prepínať proces v závislosti od podmienky alebo ak chcete prvky, ktoré nespĺňajú podmienku, spracovať inak, ako v prípade if else, použite trojčlenný operátor.

V jazyku Python možno ternárny operátor zapísať takto

Value When True if Conditional Expression else Value When False

Používa sa vo výrazovej časti zápisu porozumenia zoznamu, ako je znázornené nižšie.

[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]

Príklad je uvedený spolu s ekvivalentným príkazom for.

odd_even = ['odd' if i % 2 == 1 else 'even' for i in range(10)]
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
odd_even = []
for i in range(10):
    if i % 2 == 1:
        odd_even.append('odd')
    else:
        odd_even.append('even')

print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

Výrazy je možné písať aj pomocou ľubovoľných názvov premenných pre hodnoty true a false.

Ak je podmienka splnená, vykoná sa určité spracovanie, inak sa hodnota pôvodného iterovateľného objektu ponechá nezmenená.

odd10 = [i * 10 if i % 2 == 1 else i for i in range(10)]
print(odd10)
# [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]

Kombinácia s funkciami zip() a enumerate()

Medzi užitočné funkcie, ktoré sa často používajú v príkaze for, patria zip(), ktorá kombinuje viaceré iterable, a enumerate(), ktorá vracia hodnotu spolu s jej indexom.

Samozrejme, je možné použiť funkcie zip() a enumerate() s notáciou pre porozumenie zoznamu. Nie je to špeciálna syntax a nie je to zložité, ak si uvedomíte korešpondenciu s príkazom for.

Príklad funkcie zip().

l_str1 = ['a', 'b', 'c']
l_str2 = ['x', 'y', 'z']

l_zip = [(s1, s2) for s1, s2 in zip(l_str1, l_str2)]
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
l_zip = []
for s1, s2 in zip(l_str1, l_str2):
    l_zip.append((s1, s2))

print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]

Príklad funkcie enumerate().

l_enu = [(i, s) for i, s in enumerate(l_str1)]
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
l_enu = []
for i, s in enumerate(l_str1):
    l_enu.append((i, s))

print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]

Myšlienka je rovnaká ako predtým pri použití if.

l_zip_if = [(s1, s2) for s1, s2 in zip(l_str1, l_str2) if s1 != 'b']
print(l_zip_if)
# [('a', 'x'), ('c', 'z')]

Každý prvok možno použiť aj na výpočet nového prvku.

l_int1 = [1, 2, 3]
l_int2 = [10, 20, 30]

l_sub = [i2 - i1 for i1, i2 in zip(l_int1, l_int2)]
print(l_sub)
# [9, 18, 27]

zápis vnoreného zoznamu

Podobne ako vnorené cykly for, aj zápis porozumenia zoznamu môže byť vnorený.

[Expression for Variable Name 1 in Iterable Object 1
    for Variable Name 2 in Iterable Object 2
        for Variable Name 3 in Iterable Object 3 ... ]

Kvôli pohodliu boli pridané zalomenia a odsadenia riadkov, ktoré však nie sú potrebné pre gramatiku; môžu pokračovať na jednom riadku.

Príklad je uvedený spolu s ekvivalentným príkazom for.

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
flat = []
for row in matrix:
    for x in row:
        flat.append(x)

print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Je možné použiť aj viacero premenných.

cells = [(row, col) for row in range(3) for col in range(2)]
print(cells)
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

Môžete tiež vykonávať podmienené vetvenie.

cells = [(row, col) for row in range(3)
         for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]

Pre každý iterovateľný objekt je tiež možné podmienečne vetviť.

cells = [(row, col) for row in range(3) if row % 2 == 0
         for col in range(2) if col % 2 == 0]
print(cells)
# [(0, 0), (2, 0)]

notácia zahrnutia množiny(Set comprehensions)

Zmenou hranatých zátvoriek [] v zápise chápania zoznamu na kučeravé zátvorky {} sa vytvorí množina (objekt typu množina).

{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}

print(s)
# {0, 1, 4, 9, 16}

slovníková inklúzia(Dict comprehensions)

Slovníky (objekty typu dict) možno vytvárať aj pomocou notácie porozumenia.

{} a vo výrazovej časti zadajte kľúč a hodnotu ako key: value.

{Key: Value for Any Variable Name in Iterable Object}

Pre kľúč a hodnotu možno zadať ľubovoľný výraz.

l = ['Alice', 'Bob', 'Charlie']

d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}

Ak chcete vytvoriť nový slovník zo zoznamu kľúčov a hodnôt, použite funkciu zip().

keys = ['k1', 'k2', 'k3']
values = [1, 2, 3]

d = {k: v for k, v in zip(keys, values)}
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}

typ generátora(Generator expressions)

Ak sa hranaté zátvorky [] v notácii zoznamov použijú ako okrúhle zátvorky (), namiesto tuple sa vráti generátor. Toto sa nazýva generátor výrazov.

Príklad zápisu porozumenia zoznamu.

l = [i**2 for i in range(5)]

print(l)
# [0, 1, 4, 9, 16]

print(type(l))
# <class 'list'>

Príklad výrazu generátora. Ak vypíšete() generátor tak, ako je, nevypíše svoj obsah, ale ak ho spustíte s príkazom for, môžete získať jeho obsah.

g = (i**2 for i in range(5))

print(g)
# <generator object <genexpr> at 0x10af944f8>

print(type(g))
# <class 'generator'>

for i in g:
    print(i)
# 0
# 1
# 4
# 9
# 16

Generátorové výrazy umožňujú aj podmienené vetvenie a vnorenie pomocou zápisu if, ako aj zápisu porozumenia zoznamu.

g_cells = ((row, col) for row in range(0, 3)
           for col in range(0, 2) if col == row)

print(type(g_cells))
# <class 'generator'>

for i in g_cells:
    print(i)
# (0, 0)
# (1, 1)

Ak sa napríklad zoznam s veľkým počtom prvkov vygeneruje pomocou zápisu porozumenia zoznamu a potom sa zacyklí pomocou príkazu for, zoznam obsahujúci všetky prvky sa vygeneruje na začiatku, ak sa použije zápis porozumenia zoznamu. Na druhej strane, ak sa použije výraz generátora, pri každom opakovaní cyklu sa prvky generujú po jednom, čím sa zníži množstvo použitej pamäte.

Ak je generátorový výraz jediným argumentom funkcie, okrúhle zátvorky () možno vynechať.

print(sum([i**2 for i in range(5)]))
# 30

print(sum((i**2 for i in range(5))))
# 30

print(sum(i**2 for i in range(5)))
# 30

Pokiaľ ide o rýchlosť spracovania, zápis s porozumením zoznamu je často rýchlejší ako zápis generátora, keď sa spracúvajú všetky prvky.

Avšak napríklad pri posudzovaní pomocou all() alebo any() sa výsledok určuje podľa toho, či je prítomná hodnota false alebo true, takže použitie generátorových výrazov môže byť rýchlejšie ako použitie zápisu porozumenia zoznamu.

Neexistuje zápis porozumenia tuplov, ale ak použijete generátorový výraz ako argument funkcie tuple(), môžete generovať tuple v zápise porozumenia.

t = tuple(i**2 for i in range(5))

print(t)
# (0, 1, 4, 9, 16)

print(type(t))
# <class 'tuple'>
Copied title and URL