Cvičení č. 16 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2024/25)¶
V minulém díle jste viděli…¶
Iterovatelné objekty (iterables) v Pythonu jsou objekty, přes které může být provedena iterace, např. pomocí for
-cyklu. Mezi iterovatelné objekty patří např. kontejnery. Za iteraci na iterovatelném objektu je zodpovědný objekt zvaný iterátor, který postupně poskytuje jednotlivé prvky iterovatelného objektu.
Iterátor pro daný iterovatelný objekt získáme pomocí vestavěné funkce iter(iterable)
, další prvek v iteraci získáme pomocí funkce next(iterator)
. Jakmile iterátor poskytne všechny prvky iterovatelného objektu, vyvolá výjimku StopIteraion
, což iteraci ukončí:
my_list = [1, 5, 4]
my_iterator = iter(my_list)
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
1 5 4
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) Cell In[1], line 7 5 print(next(my_iterator)) 6 print(next(my_iterator)) ----> 7 print(next(my_iterator)) StopIteration:
V programech s iterátory často nepracujeme přímo, ale skrytě - na iterátorech je založený for
-cyklus:
my_list = [1, 8, 3]
for x in my_list:
... # do something
Kód v předchozí buňce můžeme přepsat tímto způsobem:
my_list = [1, 8, 3]
iterator = iter(my_list)
while True:
try:
x = next(iterator)
... # do something
except StopIteration:
break
# další ukázka
my_list = [1, 8, 3]
i = iter(my_list)
r = reversed(my_list)
print(i)
print(r)
new_list = list(reversed(my_list))
print(new_list)
for x in r:
print(x, end = " ")
print("")
for x in reversed(my_list):
print(x, end = " ")
<list_iterator object at 0x704f70bee5c0> <list_reverseiterator object at 0x704f7012d5a0> [3, 8, 1] 3 8 1 3 8 1
Seznámili jsme se s několika užitečnými vestavěnými funkcemi v Pythonu, které vrací iterátory:
Funkce | Krátký popis |
---|---|
reversed(sequence) |
Vrací iterátor, který poskytuje prvky posloupnosti sequence v opačném pořadí. |
map(function, iterable) |
Vrací iterátor přes function(x) pro x z iterable . |
filter(function, iterable) |
Vrací iterátor přes ta x z iterable , pro která function(x)==True . |
zip(*iterables) |
Vrací iterátor přes n-tice (x, y,...) pro x z iterable1 , y z iterable2 ,... |
enumerate(iterable,start=0) |
Vrací objekt enumerate - iterátor přes dvojice (index, x) pro x z iterable . |
A s dalšími vestavěnými funkcemi nad iterovatelnými objekty:
Funkce | Krátký popis |
---|---|
sorted(iterable, /, *, key=None, reverse=False ) |
Vrací setříděný seznam prvků z iterable . |
all(iterable) |
Vrací True , pokud každý prvek z iterable má hodnotu True , jinak vrací False . |
any(iterable) |
Vrací True , pokud alespoň jeden prvek z iterable má hodnotu True , jinak vrací False . |
sum(iterable,/,start=0) |
Vrací součet prvků z iterable . |
max(iterable,/,key=None) |
Vrací největší prvek z iterable . |
min(iterable,/,key=None) |
Vrací nejmenší prvek z iterable . |
range(stop) , range(start,stop) , range(start,stop,step) |
Vrací iterovatelný objekt typu range , nemodifikovatelnou posloupnost čísel. |
Generátory¶
Generátory jsou zvláštním druhem iterátoru, který neiteruje přes existující iterovatelný objekt, ale přes průběžně generované hodnoty. Můžeme ho vytvořit pomocí tzv. generátorové funkce (generator function) nebo pomocí tzv. generátorového výrazu (generator expression).
Generátorová funkce je taková funkce, která hodnoty nevrací (pomocí příkazu return
), ale generuje (pomocí příkazu yield
). Například:
def generate_squares(n):
for x in range(n):
yield x ** 2
Kdykoliv v programu zavoláme generátorovou funkci, funkce vrátí nový generátor - tj. iterátor, který iteruje přes hodnoty generované pomocí yield
.
m = generate_squares(5)
print(m)
<generator object generate_squares at 0x704f6a169be0>
for x in m:
print(x, end = " ")
0 1 4 9 16
# generátor se použitím vyčerpává:
m = generate_squares(5)
for x in m:
print(x, end = " ")
print("\npodruhé")
for x in m:
print(x, end = " ")
0 1 4 9 16 podruhé
Podrobněji:
Generátor si pamatuje aktuální pozici v rámci funkce. Při volání next()
iterátor spustí generátorovou funkci od aktuální pozice. Provádění příkazů přeruší u příkazu yield
a jako návratovou hodnotu funkce next()
poskytne příslušnou hodnotu. Při dalším volání next()
funkce pokračuje dál od daného místa. Například:
def generate_whatever():
x = 1
#print("dej", x)
yield x
x = 2
#print("dej", x)
yield x
#print("dej neco")
yield "the end"
m = generate_whatever()
print(m)
<generator object generate_whatever at 0x704f7154bdc0>
# opět si zkuste pustit tuto buňku opakovaně:
print(next(m))
1
# generátor můžeme převést na iterovatelný objekt:
s = list(generate_whatever())
print(s)
[1, 2, 'the end']
# nebo přes něj můžeme iterovat:
for x in generate_whatever():
print(x)
1 2 the end
# další ukázka: generátor hodnot od 0 do n-1:
def my_range(n):
i = 0
while i < n:
yield i
i = i + 1
for x in my_range(21):
print(x, end = " ")
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Poznámka: Generátory šetří časové i paměťové nároky programu: nemusíme uchovávat všechna data v paměti najednou (např. v kontejneru), hodnoty jsou generované jedna po druhé až ve chvíli, kdy jsou potřeba.
Příklady¶
1a. Generátor dělitelů. Napište generátorovou funkci, která vrátí generátor všech dělitelů zadaného přirozeného čísla n. Čísla budou generována v pořadí od nejmenšího po největší.
def divisors_generator(n):
i = 1
while i <= n:
if n % i == 0:
yield i
i = i + 1
def divisors_generator(n):
for i in range(1, n+1):
if n % i == 0:
yield i
n = 24
for divisor in divisors_generator(n):
print(divisor, end=' ')
print("")
print(list(divisors_generator(504)))
assert list(divisors_generator(504)) == [1, 2, 3, 4, 6, 7, 8, 9, 12, 14, 18, 21, 24, 28, 36, 42, 56, 63, 72, 84, 126, 168, 252, 504]
1 2 3 4 6 8 12 24 [1, 2, 3, 4, 6, 7, 8, 9, 12, 14, 18, 21, 24, 28, 36, 42, 56, 63, 72, 84, 126, 168, 252, 504]
2a. Generátor posloupnosti Napište generátorovou funkci, která vrátí generátor prvků následující posloupnosti (pro dané n): 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 ... 1 2 ... n.
def sequence_generator(n):
for i in range(1, n+1):
for j in range(1, i+1):
yield j
n = 5
generator = sequence_generator(n)
for num in generator:
print(num, end=' ')
print("")
print(list(sequence_generator(8)))
assert list(sequence_generator(8)) == [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8]
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8]
4a. Generátor délek slov. Naprogramujte generátorovou funkci, která vrátí generátor délek všech slov v textu. Předpokládejme, že slova jsou oddělená pomocí obyčejných mezer (možná několika za sebou). Hodit se mohou i metody pro stringy (např. split()
).
def word_lengths_generator(text):
for slovo in text.split():
yield len(slovo)
text = "Toto je příklad textu s několika slovy oddělenými mezerami"
for length in word_lengths_generator(text):
print(length, end=' ')
assert (list(word_lengths_generator(text)) == [4, 2, 7, 5, 1, 8, 5, 10, 8])
4 2 7 5 1 8 5 10 8
Generátorové výrazy a generátorová notace modifikovatelných kontejnerů¶
Generátorové výrazy umožňují vytvářet jednoduché generátory elegantně bez nutnosti vytváření generátorových funkcí. Generátorová notace (comprehension) u modifikovatelných (mutable) kontejnerů (list, set, dict) nám pak výrazně zjednodušuje vytváření a zpracování těchto objektů.
Základní syntaxe je následující:
python:
new_generator = (expression for member in iterable)
new_list = [expression for member in iterable]
new_set = {expression for member in iterable}
new_dict = {key:expression for member in iterable}
Výrazy se liší jen typem použitých závorek. Pokud použijeme kulaté závorky, bude výsledkem generátor, jinak příslušný kontejner. Použitou syntaxi si vysvětlíme na několika následujících příkladech:
Například pro seznam příkaz s = [expression for member in iterable]
můžeme přepsat jako:
python:
s = []
for member in iterable:
s.append(expression)
Obdobně pro množinu s = {expression for member in iterable}
:
python:
s = set()
for member in iterable:
s.add(expression)
Pro slovník d = {key:expression for member in iterable}
:
python:
d = {}
for member in iterable:
d[key] = expression
Ukážeme si to na konkrétních příkladech:
# generátorová notace seznamu:
my_tuple = (1, 8, 3)
s = [x for x in my_tuple]
print(s)
s = [1 for x in my_tuple]
print(s)
s = [x**2 for x in my_tuple]
print(s)
[1, 8, 3] [1, 1, 1] [1, 64, 9]
# totéž bez generátorové notace:
my_tuple = (1, 8, 3)
my_list = [x*2 for x in my_tuple]
my_list1 = []
for x in my_tuple:
my_list1.append(x*2)
print(my_list, my_list1)
[2, 16, 6] [2, 16, 6]
# generátorová notace množiny:
my_tuple = (1, 8, 3)
s = {x for x in my_tuple}
print(s)
s = {1 for x in my_tuple}
print(s)
s = {x**2 for x in my_tuple}
print(s)
{8, 1, 3} {1} {64, 1, 9}
# generátorová notace seznamu, množiny a slovníku:
my_tuple = (1,8,3)
my_list = [x*2 for x in my_tuple]
my_set = {x*2 for x in my_tuple}
my_dict = {x:x*2 for x in my_tuple}
print(my_tuple)
print(my_list)
print(my_set)
print(my_dict)
(1, 8, 3) [2, 16, 6] {16, 2, 6} {1: 2, 8: 16, 3: 6}
# Nová ntice:
my_tuple = (1,8,3)
# chci novou ntici, kde budou prvky vynásobené dvěma:
t = ()
for x in my_tuple :
t += (x*2, )
print(t)
# o trochu efektivnější:
s = []
for x in my_tuple :
s.append(x*2)
t = tuple(s)
print(t)
# nejefektivněji a na jeden řádek:
t = tuple(x*2 for x in my_tuple)
print(t)
(2, 16, 6) (2, 16, 6) (2, 16, 6)
# generátorový výraz:
my_generator = (x**2 for x in my_tuple)
print(my_generator)
for x in my_generator:
print(x, end = " ")
print("")
# generátorový výraz přímo ve for-cyklu:
for y in (x**2 for x in my_tuple):
print(y, end = " ")
<generator object <genexpr> at 0x704f683a9560> 1 64 9 1 64 9
# generátor převedu na seznam:
my_generator = (x*2 for x in my_tuple)
my_list = list(my_generator)
print(my_list)
# zkráceně:
my_list = list(x*2 for x in my_tuple)
print(my_list)
# je to samé ještě jednou:
my_list = [x*2 for x in my_tuple]
print(my_list)
[2, 16, 6] [2, 16, 6] [2, 16, 6]
Výraz my_generator = (x**2 for x in my_tuple)
je zkratkou následujícího kódu:
# generátorová funkce:
def generate_squares(source):
for x in source:
yield x ** 2
def generate_squares1(source):
return (x**2 for x in source)
my_generator = generate_squares(my_tuple)
my_generator1 = generate_squares1(my_tuple)
print(my_generator, my_generator1)
<generator object generate_squares at 0x70395041b2a0> <generator object generate_squares1.<locals>.<genexpr> at 0x70395041b370>
Výraz new_list = [expression for member in iterable]
můžeme ekvivalentně zapsat jako:
new_list = list(expression for member in iterable)
. Obdobně pro množinu. Pro slovník bude syntaxe lehce odlišná - argumentem funkce dict
může být generátor dvojic (klíč, hodnota)
:
my_tuple = (1,8,3)
my_list = list(x*2 for x in my_tuple)
my_set = set(x*2 for x in my_tuple)
my_dict = dict((x, x*2) for x in my_tuple)
print(my_tuple)
print(my_list)
print(my_set)
print(my_dict)
my_list = [x*2 for x in my_tuple]
my_set = {x*2 for x in my_tuple}
my_dict = {x: x*2 for x in my_tuple}
print(my_tuple)
print(my_list)
print(my_set)
print(my_dict)
(1, 8, 3) [2, 16, 6] {16, 2, 6} {1: 2, 8: 16, 3: 6} (1, 8, 3) [2, 16, 6] {16, 2, 6} {1: 2, 8: 16, 3: 6}
Generové výrazy můžeme rozšířit o podmínky a můžeme pomocí nich kombinovat hodnoty z více zdrojů:
- Filtrování (obdoba funkce
filter
):
python:
(expression for member in iterable if condition)
- Kombinace hodnot z více zdrojů:
python:
(expression for member1 in iterable1 (if condition1)
for member2 in iterable2 (if condition2)
...
for memberN in iterableN (if conditionN))
Příkaz s = [f(x) for x in iterable if condition]
je zkratkou za:
python:
s = []
for x in iterable:
if condition:
s.add(f(x))
Příkaz s = [x+y for x in range(5) for y in range(x)]
je zkratkou za:
python:
s = []
for x in range(5):
for y in range(x):
s.append(x+y)
Opět si to ukážeme na konkrétních příkladech:
# generátorová notace seznamu (list comprehension):
s = [x for x in range(1, 11)]
print(s, end ="\n\n")
t = [2 ** x for x in range(1, 11)]
print(t, end ="\n\n")
# generátorová notace množiny (set comprehension) s podmínkou:
m = {x for x in s if x % 2== 0}
print(m, end ="\n\n")
# generátorová notace seznamu s více zdroji:
trojice =[(i,j,k) for i in [1, 2, 3] for j in {True, False} for k in "AB"]
print(trojice, end ="\n\n")
# generátorová notace seznamu s využitím funkce zip:
trojice =[(i,j,k) for (i,j,k) in zip([1,2,3], {True, False},"AB")]
print(trojice, end ="\n\n")
# generátorová notace slovníku:
šachovnice ={(i, j) : "" for i in "abcdefgh" for j in range(1, 8)}
šachovnice["c", 4] = "bílý pěšec"
šachovnice["a", 1] = "černý král"
print(šachovnice)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] {2, 4, 6, 8, 10} [(1, False, 'A'), (1, False, 'B'), (1, True, 'A'), (1, True, 'B'), (2, False, 'A'), (2, False, 'B'), (2, True, 'A'), (2, True, 'B'), (3, False, 'A'), (3, False, 'B'), (3, True, 'A'), (3, True, 'B')] [(1, False, 'A'), (2, True, 'B')] {('a', 1): 'černý král', ('a', 2): '', ('a', 3): '', ('a', 4): '', ('a', 5): '', ('a', 6): '', ('a', 7): '', ('b', 1): '', ('b', 2): '', ('b', 3): '', ('b', 4): '', ('b', 5): '', ('b', 6): '', ('b', 7): '', ('c', 1): '', ('c', 2): '', ('c', 3): '', ('c', 4): 'bílý pěšec', ('c', 5): '', ('c', 6): '', ('c', 7): '', ('d', 1): '', ('d', 2): '', ('d', 3): '', ('d', 4): '', ('d', 5): '', ('d', 6): '', ('d', 7): '', ('e', 1): '', ('e', 2): '', ('e', 3): '', ('e', 4): '', ('e', 5): '', ('e', 6): '', ('e', 7): '', ('f', 1): '', ('f', 2): '', ('f', 3): '', ('f', 4): '', ('f', 5): '', ('f', 6): '', ('f', 7): '', ('g', 1): '', ('g', 2): '', ('g', 3): '', ('g', 4): '', ('g', 5): '', ('g', 6): '', ('g', 7): '', ('h', 1): '', ('h', 2): '', ('h', 3): '', ('h', 4): '', ('h', 5): '', ('h', 6): '', ('h', 7): ''}
Příklady¶
Předně můžete zkusit naprogramovat příklady z minulého cvičení tak, aby místo funkcí map
a filter
používaly generátory.
1b. Seznam dělitelů. Napište funkci, která vrátí seznam všech dělitelů zadaného přirozeného čísla seřazený od nejmenšího po největší. Úlohu řeště tentokrát pomocí generátorové notace seznamu (list comprehension). Příklad navazuje na příklad 1a výše.
# připomenutí: generátorová funkce
def divisors_generator(n):
for i in range(1, n+1):
if n % i == 0:
yield i
def divisors_list(n):
return [ i for i in range(1, n + 1) if n % i == 0 ]
n = 24
for divisor in divisors_list(n):
print(divisor, end=' ')
assert divisors_list(504) == [1, 2, 3, 4, 6, 7, 8, 9, 12, 14, 18, 21, 24, 28, 36, 42, 56, 63, 72, 84, 126, 168, 252, 504]
1 2 3 4 6 8 12 24
1c. Generátor dělitelů podruhé. Šla by předchozí funkce jednoduše upravit tak, aby místo seznamu dělitelů vracela generátor dělitelů?
def divisors_generator(n):
return (i for i in range(1, n + 1) if n % i == 0)
print(divisors_generator(n))
n = 24
for divisor in divisors_generator(n):
print(divisor, end=' ')
assert list(divisors_generator(504)) == [1, 2, 3, 4, 6, 7, 8, 9, 12, 14, 18, 21, 24, 28, 36, 42, 56, 63, 72, 84, 126, 168, 252, 504]
<generator object divisors_generator.<locals>.<genexpr> at 0x70394a1792f0> 1 2 3 4 6 8 12 24
2b. Generátor posloupnosti podruhé Napište funkci, která vrátí generátor prvků následující posloupnosti (pro dané n): 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 ... 1 2 ... n. Tentokrát úlohu řešte pomocí generátorového výrazu. Funkce bude vracet generátor. Příklad navazuje na příklad 2a výše.
# připomenutí: generátorová funkce
def sequence(n):
for i in range(1, n+1):
for j in range(1, i+1):
yield(j)
print(list(sequence(n)))
[1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5]
def sequence(n):
return (j for i in range(1, n+1) for j in range(1, i+1))
n = 8
nums = sequence(n)
for num in nums:
print(num, end=' ')
print(list(sequence(n)))
nums = sequence(n)
assert list(nums) == [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8]
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8]
- Prohoď klíče a hodnoty. Naprogramujte funkci, která na základě slovníku vytvoří nový slovník, kde budou prohozené klíče a hodnoty. Úlohu řešte pomocí generátorové generátorové notace slovníku.
def swap_keys_and_values(input_dict):
return {input_dict[key]:key for key in input_dict}
def swap_keys_and_values(input_dict):
return {value:key for (key, value) in input_dict.items()}
original_dict = {'a': 1, 'b': 2, 'c': 3}
swapped_dict = swap_keys_and_values(original_dict)
print(swapped_dict)
assert swapped_dict == {1: 'a', 2: 'b', 3: 'c'}
{1: 'a', 2: 'b', 3: 'c'}
4b. Délka slov. Naprogramujte funkci, která zjistí délku každého slova v textu. Předpokládejme, že slova jsou oddělená pomocí obyčejných mezer (možná několika za sebou). Úlohu řešte tentokrát pomocí generátorového výrazu nebo generátorové notace seznamu. Funkce bude vracet generátor nebo seznam. Hodit se mohou i metody pro stringy (např. split()
).
def word_lengths(text):
return ( len(word) for word in text.split())
text = "Toto je příklad textu s několika slovy oddělenými mezerami"
for length in word_lengths(text):
print(length, end=' ')
print(list(word_lengths(text)))
assert (list(word_lengths(text)) == [4, 2, 7, 5, 1, 8, 5, 10, 8])
4 2 7 5 1 8 5 10 8 [4, 2, 7, 5, 1, 8, 5, 10, 8]
4c. Jen krátká slova. Naprogramujte funkci, která z textu odstraní všechna moc dlouhá slova, tj. slova, která jsou delší než n
písmen.
Předpokládejme, že slova jsou oddělená pomocí obyčejných mezer. Úlohu řešte s využitím generátorové notace. Hodit se mohou i metody pro stringy (např. join()
a split()
).
def remove_long_words(text, n):
return " ".join(word for word in text.split() if len(word) <= n)
text = "Toto je příklad textu s několika slovy oddělenými mezerami"
new_text = remove_long_words(text, 6)
print(new_text)
assert remove_long_words(text, 6) == "Toto je textu s slovy"
Toto je textu s slovy
4d. Zkrať moc dlouhá slova. Naprogramujte funkci, která z textu zkrátí na n
písmen všechna moc dlouhá slova, tj. slova, která jsou delší než n
písmen.
Předpokládejme, že slova jsou oddělená pomocí obyčejných mezer. Úlohu řešte s využitím generátorové notace. Hodit se mohou i metody pro stringy (např. join()
a split()
).
def shorten_long_words(text, n):
return " ".join(word[:n] for word in text.split() )
text = "Toto je příklad textu s několika slovy oddělenými mezerami"
new_text = shorten_long_words(text,6)
print(new_text)
assert shorten_long_words(text,6) == "Toto je příkla textu s několi slovy odděle mezera"
Toto je příkla textu s několi slovy odděle mezera
- Bláznivé křížení zvířat podruhé. Máme dva seznamy
s
,t
s názvy zvířat. Napište funkcimerge_animals(s, t)
, která vytvoří nový seznam, který bude obsahovat "zkřížené" názvy zvířat tak, že z prvního názvu vezmeme vždy první polovinu a z druhého druhou polovinu. Např. 'hroch' a 'tigr' -> 'hrogr'. Úlohu řešte tentokrát pomocí generátorové notace. Hodit se může i funkcezip()
.
def merge_animals(s, t):
return [a[:len(a)//2] + b[len(b)//2:] for a, b in zip(s, t)]
print(merge_animals(["hroch","potkan"],["žirafa","orangutan","lev"]))
assert merge_animals(["hroch","potkan"],["žirafa","orangutan","lev"]) == ['hrafa', 'potgutan']
['hrafa', 'potgutan']
- Frekvenční analýza písmen. Napište funkci
freq_analysis(text)
, která spočítá výskyt jednotlivých písmen (znaků) ve vstupním textu a vrátí výsledek jako slovník s prvkypísmeno: počet výskytů
. Malá a velká písmena nebudeme rozlišovat. Úlohu řešte tentokrát pomocí generátorové notace slovníku. Hodit se mohou i různé metody pro stringy (např.count()
,lower()
,upper()
neboisalpha()
). Písmena a počty jejich výskytů vypište setříděné sestupně podle počtu výskytů.
def freq_analysis(text):
return {char: text.count(char) for char in set(text.lower()) if char.isalpha()}
d = freq_analysis("All the world is a stage and all the men and women merely players.")
print(d)
print(sorted(d.items()))
# vypište setříděné sestupně podle počtu výskytů:
for (x, y) in sorted(d.items(), key=lambda x: x[1], reverse=True):
print(f"{x} : {y}, ")
{'o': 2, 'l': 7, 'a': 6, 'h': 2, 's': 3, 'm': 3, 'n': 4, 'e': 8, 't': 3, 'w': 2, 'd': 3, 'g': 1, 'p': 1, 'i': 1, 'y': 2, 'r': 3} [('a', 6), ('d', 3), ('e', 8), ('g', 1), ('h', 2), ('i', 1), ('l', 7), ('m', 3), ('n', 4), ('o', 2), ('p', 1), ('r', 3), ('s', 3), ('t', 3), ('w', 2), ('y', 2)] e : 8, l : 7, a : 6, n : 4, s : 3, m : 3, t : 3, d : 3, r : 3, o : 2, h : 2, w : 2, y : 2, g : 1, p : 1, i : 1,
- Frekvenční analýza slov. Napište funkci
freq_analysis_words(text)
, která spočítá výskytů jednotlivých slov ve vstupním textu a vrátí výsledek jako slovník s prvkyslovo: počet výskytů
. Malá a velká písmena nebudeme rozlišovat. Úlohu řešte tentokrát pomocí generátorové notace slovníku. Hodit se mohou i různé metody pro stringy (např.count()
,lower()
,upper()
nebosplit()
). Slova a počty výskytů vypište setříděné vzestupně podle abecedy.
def freq_analysis(text):
...
d = freq_analysis("This is a test. This is only a test, not a real situation.")
print(d)
# vypište setříděné vzestupně podle abecedy:
...
- indexy Napište funkci, která vrátí seznam všech indexů, kde se v řetězci
string
vyskytuje znakchar
. Úlohu řešte tentokrát pomocí generátorové notace seznamu nebo generátorové funkce. Hodit se může i funkceenumerate()
.
# generátorová notace:
def find_letter_indexes(string, letter):
...
print(find_letter_indexes("hello world", "l"))
assert find_letter_indexes("hello world", "l") == [2, 3, 9]
# generátorová funkce:
def generate_letter_indexes(string, letter):
...
print(list(generate_letter_indexes("hello world", "l")))
assert list(generate_letter_indexes("hello world", "l")) == [2, 3, 9]
8b. indexy Napište funkci, která vrátí seznam všech indexů, na kterých v řetězci string
začíná podstring substring
. Úlohu řešte tentokrát pomocí generátorové notace seznamu nebo generátorové funkce. Hodit se může i funkce enumerate()
.
def find_substring_indexes(string, substring):
...
print(find_substring_indexes("ara aaraara arara", "ara"))
assert find_substring_indexes("ara aaraara arara", "ara") == [0, 5, 8, 12, 14]
# generátorová funkce:
def generate_substring_indexes(string, substring):
...
print(list(generate_letter_indexes("ara aaraara arara", "ara")))
assert list(generate_letter_indexes("ara aaraara arara", "ara")) == [0, 5, 8, 12, 14]