Obsah
1. Kontejner Counter ze standardní knihovny
2. Konstrukce kontejneru Counter
3. Inicializace počitadel prvků
4. Spojení kontejnerů typu Counter, rozdíl mezi obsahem dvou kontejnerů
5. Výpočet frekvence slov v textu s využitím kontejneru Counter
6. Výpočet frekvence znaků v textu
7. Převod hodnot z kontejneru Counter do seznamu a slovníku
10. Konstrukce kontejneru Multiset
11. Specifikace počtu shodných prvků při konstrukci multimnožiny
12. Převod mezi kontejnerem Counter a multimnožinou
13. Spojení multimnožin, multimnožina vzniklá opakováním jiné multimnožiny
15. Multimnožiny a multimnožinové operace
17. Instalace balíčku multidict
18. Základní operace s multislovníky
19. Repositář s demonstračními příklady
1. Kontejner Counter ze standardní knihovny
Velmi užitečným, i když poněkud méně známým kontejnerem, který můžeme nalézt ve standardní knihovně Pythonu, je kontejner nazvaný Counter. Pro každý prvek uložený v tomto kontejneru se kromě hodnoty prvku navíc pamatuje i počet opakování prvku, takže na Counter můžeme pohlížet jako na specializovaný slovník, v němž jsou prvky uloženy ve formě klíčů a hodnoty obsahují počet opakování daného prvku. Kontejner Counter ovšem navíc nabízí i metody určené pro zpracování počtu opakování prvku, jak to ostatně uvidíme i na demonstračních příkladech, které budou ukázány v navazujících kapitolách.
O tom, že je Counter skutečně kontejnerem, se můžeme přesvědčit velmi snadno testem na existenci metody __contains__:
>>> from collections import Counter >>> dir(Counter) ['__add__', '__and__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__le__', '__len__', '__lt__', '__missing__', '__module__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__weakref__', '_keep_positive', 'clear', 'copy', 'elements', 'fromkeys', 'get', 'items', 'keys', 'most_common', 'pop', 'popitem', 'setdefault', 'subtract', 'total', 'update', 'values']
2. Konstrukce kontejneru Counter
Konstrukce kontejneru Counter je snadná. V případě, že má být tento kontejner na začátku prázdný, postačuje zavolat konstruktor Counter bez parametrů:
from collections import Counter c = Counter() print(c)
Výsledek získaný po spuštění dnešního prvního demonstračního skriptu:
Counter()
Do kontejneru Counter je ovšem možné již při jeho konstrukci vložit nějaké prvky. Je například umožněno předat seznam těchto prvků, a to následujícím způsobem:
from collections import Counter c = Counter(["foo", "bar", "baz"]) print(c)
Výsledek bude v tomto případě vypadat následovně. Povšimněte si, že počitadlo u každého prvku je nastaveno na jedničku a nikoli na nulu (to lze ovšem změnit):
Counter({'foo': 1, 'bar': 1, 'baz': 1})
Podobným způsobem můžeme konstruktoru Counter předat i n-tici (tuple) či množinu (set) prvků tak, jak je to ukázáno na následující dvojici demonstračních příkladů. V případě předání n-tice je nutné kulaté závorky zdvojit, protože vnější dvojice závorek představuje volání funkce a vnitřní dvojice definici n-tice:
from collections import Counter c = Counter(("foo", "bar", "baz")) print(c)
Výsledek:
Counter({'foo': 1, 'bar': 1, 'baz': 1})
Předání množiny do konstruktoru:
from collections import Counter c = Counter({"foo", "bar", "baz"}) print(c)
Výsledek:
Counter({'foo': 1, 'baz': 1, 'bar': 1})
3. Inicializace počitadel prvků
A konečně můžeme kontejner Counter inicializovat tak, že mu předáme slovník, který obsahuje předvyplněné čítače prvků. Volání tedy v takovém případě vypadá následovně:
from collections import Counter c = Counter({"foo": 0, "bar": 1, "baz": 2}) print(c)
Výsledkem bude naplněný kontejner:
Counter({'baz': 2, 'bar': 1, 'foo': 0})
Sice je možné předat slovník, který kromě celočíselných údajů obsahuje hodnoty jiného typu, ovšem v takovém případě nebudou plně funkční další operace, s nimiž se seznámíme v navazujícím textu.
4. Spojení kontejnerů typu Counter, rozdíl mezi obsahem dvou kontejnerů
Dva kontejnery typu Counter lze spojit s využitím standardního (přetíženého) operátoru „+“. Výsledkem bude nový kontejner stejného typu, který bude obsahovat prvky z obou kontejnerů i jejich čítače. Pokud nějaký prvek existuje v obou zdrojových kontejnerech, jsou jeho čítače sečteny, což je ostatně patrné i z následujícího zdrojového kódu:
from collections import Counter c1 = Counter({"foo": 0, "bar": 1, "baz": 2}) print(c1) c2 = Counter(["foo", "bar", "baz", "baf"]) print(c2) c3 = c1 + c2 print(c3)
Podívejme se nyní na výsledky vypsané tímto demonstračním příkladem. Na třetím řádku je obsah výsledného kontejneru Counter, který bude obsahovat prvky z obou zdrojových kontejnerů. A počty opakování jsou získány sečtením původních čítačů:
Counter({'baz': 2, 'bar': 1, 'foo': 0}) Counter({'foo': 1, 'bar': 1, 'baz': 1, 'baf': 1}) Counter({'baz': 3, 'bar': 2, 'foo': 1, 'baf': 1})
Podobně od sebe můžeme dva kontejnery typu Counter „odečíst“, což se provádí standardním přetíženým operátorem „-“:
from collections import Counter c1 = Counter({"foo": 0, "bar": 1, "baz": 2}) print(c1) c2 = Counter(["foo", "bar", "baz", "baf"]) print(c2) c3 = c1 - c2 print(c3) c4 = c2 - c1 print(c4)
Opět se podívejme na výsledky, které jsme získali po spuštění předchozího skriptu. Nejprve jsou vypsány oba zdrojové kontejnery a poté výsledek jejich rozdílu, přičemž operace „-“ není komutativní, takže výsledky na posledních dvou řádcích budou odlišné. Zajímavé je, že pokud čítač nějakého prvku dosáhne záporné hodnoty, nebude do výsledného kontejneru vůbec vložen. A pokud prvek existuje jen v menšiteli, taktéž není do výsledného kontejneru vložen (měl by záporný čítač):
Counter({'baz': 2, 'bar': 1, 'foo': 0}) Counter({'foo': 1, 'bar': 1, 'baz': 1, 'baf': 1}) Counter({'baz': 1}) Counter({'foo': 1, 'baf': 1})
5. Výpočet frekvence slov v textu s využitím kontejneru Counter
Změna počitadla prvku (hodnoty) se provádí metodou update, které se v tom nejjednodušším případě předává seznam (resp. přesněji řečeno sekvence) s hodnotami prvků. Čítač takového prvku se zvýší o jedničku a pro původně neexistující prvek se nastaví na jedničku. Kontejnery Counter navíc nabízí uživatelům i užitečné metody total a most_common. Metoda total vrátí součet všech čítačů a metoda most_common slouží pro získání n prvků s nejvyššími hodnotami čítačů, které jsou navíc seřazeny podle těchto hodnot.
Toho můžeme využít například pro zjištění četnosti slov v nějakém textovém dokumentu. Implementace skriptu pro získání této statistiky může vypadat následovně:
from collections import Counter c = Counter() print(c) sentences = """ Počátek každodenní práce na poli formování pozice vyžaduje návrh a realizaci směru progresivního rozvoje. Na druhé straně rámec stavu a vývoje postavení vyžadují nalezení a jednoznačné upřesnění systému masové účasti. Vzájemné postavení organizačních autorit stejně jako stabilní a kvantitativní vzrůst a sféra naší aktivity napomáhá přípravě a realizaci nových návrhů. Stejně tak stálé, informačně-propagandistické zabezpečení naší práce jednoznačně předurčuje implementaci odpovídajících podmínek aktivizace. Nesmíme však zapomínat, že konzultace se širokým aktivem vyzaduje rozšiřování logistických prostředků a forem působení. Ideové úvahy nejvyššího řádu a rovněž upřesnění a rozvoj struktur přetváří strukturu vedení dalších směrů rozvoje. Tímto způsobem komplexní analýza našich možností od nás vyžaduje analýzy systému výchovy pracovníků odpovídajících aktuálním potřebám. Závažnost těchto problémů je natolik zřejmá, že nový model organizační činnosti zvyšuje potřebu aplikace modelu rozvoje. Pestré a bohaté zkušenosti jasně říkají, že další rozvoj různých forem činnosti představuje pozoruhodný experiment prověrky možnosti nasazení veškerých dostupných prostředků. Každodenní praxe nám potvrzuje, že počátek každodenní práce na poli formování pozice ve značné míře podmiňuje vytvoření tvorby nových zdrojů. """ words = sentences.split() for word in words: c.update([word]) print(c.total()) for word in c.most_common(10): print(word[0], word[1])
Tento skript vypíše na začátku prázdný Counter a na řádku dalším pak součet všech čítačů slov. To znamená, že předaný dokument obsahuje 167 slov. A na následujících řádcích jsou vypsána jednotlivá slova a jejich četnosti. Povšimněte si, že ve skutečnosti není výsledek dokonalý, protože neodstraňujeme tečky, čárky atd.:
Counter() 167 a 10 že 4 práce 3 rozvoje. 3 každodenní 2 na 2 poli 2 formování 2 pozice 2 vyžaduje 2
6. Výpočet frekvence znaků v textu
V předchozím demonstračním příkladu se čítače slov zvyšovaly v programové smyčce, ve které se volala metoda update a té se předával jednoprvkový seznam se slovy:
for word in words: c.update([word])
Pokusme se nyní zjistit, co se stane v případě, že namísto seznamu přímo předáme hodnotu uloženou v proměnné word, což je řetězec:
from collections import Counter c = Counter() print(c) sentences = """ Počátek každodenní práce na poli formování pozice vyžaduje návrh a realizaci směru progresivního rozvoje. Na druhé straně rámec stavu a vývoje postavení vyžadují nalezení a jednoznačné upřesnění systému masové účasti. Vzájemné postavení organizačních autorit stejně jako stabilní a kvantitativní vzrůst a sféra naší aktivity napomáhá přípravě a realizaci nových návrhů. Stejně tak stálé, informačně-propagandistické zabezpečení naší práce jednoznačně předurčuje implementaci odpovídajících podmínek aktivizace. Nesmíme však zapomínat, že konzultace se širokým aktivem vyzaduje rozšiřování logistických prostředků a forem působení. Ideové úvahy nejvyššího řádu a rovněž upřesnění a rozvoj struktur přetváří strukturu vedení dalších směrů rozvoje. Tímto způsobem komplexní analýza našich možností od nás vyžaduje analýzy systému výchovy pracovníků odpovídajících aktuálním potřebám. Závažnost těchto problémů je natolik zřejmá, že nový model organizační činnosti zvyšuje potřebu aplikace modelu rozvoje. Pestré a bohaté zkušenosti jasně říkají, že další rozvoj různých forem činnosti představuje pozoruhodný experiment prověrky možnosti nasazení veškerých dostupných prostředků. Každodenní praxe nám potvrzuje, že počátek každodenní práce na poli formování pozice ve značné míře podmiňuje vytvoření tvorby nových zdrojů. """ words = sentences.split() for word in words: c.update(word) print(c.total()) for word in c.most_common(10): print(word[0], word[1])
Vzhledem k tomu, že řetězce jsou v Pythonu taktéž považovány za sekvence, bude výsledek odlišný, protože získáme počet znaků a četnost použití jednotlivých znaků (což je taktéž zajímavá statistika – například vysoký výskyt „o“ je možná neobvyklý):
Counter() 1152 o 92 e 86 a 86 n 84 t 57 r 54 v 53 í 46 p 44 s 42
To ovšem znamená, že vůbec nepotřebujeme programovou smyčku a můžeme celý skript pro zjištění frekvence slov přepsat do mnohem kratší podoby:
from collections import Counter c = Counter() print(c) sentences = """ ... ... ... """ words = sentences.split() c.update(words) print(c.total()) for word in c.most_common(10): print(word[0], word[1])
7. Převod hodnot z kontejneru Counter do seznamu a slovníku
Na závěr první části článku si ukažme způsob převodu kontejneru typu Counter na běžné seznamy nebo slovníky. Zajímat nás pochopitelně bude nejenom to, jestli je převod vůbec možný, ale i to, co je výsledkem takové konverze:
from collections import Counter c = Counter() print(c) sentences = """ Počátek každodenní práce na poli formování pozice vyžaduje návrh a realizaci směru progresivního rozvoje. Na druhé straně rámec stavu a vývoje postavení vyžadují nalezení a jednoznačné upřesnění systému masové účasti. Vzájemné postavení organizačních autorit stejně jako stabilní a kvantitativní vzrůst a sféra naší aktivity napomáhá přípravě a realizaci nových návrhů. Stejně tak stálé, informačně-propagandistické zabezpečení naší práce jednoznačně předurčuje implementaci odpovídajících podmínek aktivizace. Nesmíme však zapomínat, že konzultace se širokým aktivem vyzaduje rozšiřování logistických prostředků a forem působení. Ideové úvahy nejvyššího řádu a rovněž upřesnění a rozvoj struktur přetváří strukturu vedení dalších směrů rozvoje. Tímto způsobem komplexní analýza našich možností od nás vyžaduje analýzy systému výchovy pracovníků odpovídajících aktuálním potřebám. Závažnost těchto problémů je natolik zřejmá, že nový model organizační činnosti zvyšuje potřebu aplikace modelu rozvoje. Pestré a bohaté zkušenosti jasně říkají, že další rozvoj různých forem činnosti představuje pozoruhodný experiment prověrky možnosti nasazení veškerých dostupných prostředků. Každodenní praxe nám potvrzuje, že počátek každodenní práce na poli formování pozice ve značné míře podmiňuje vytvoření tvorby nových zdrojů. """ words = sentences.split() for word in words: c.update([word]) print(list(c)) print() print(dict(c))
Převodem na seznam získáme pouze seznam všech prvků a nikoli jejich čítače:
['Počátek', 'každodenní', 'práce', 'na', 'poli', 'formování', 'pozice', 'vyžaduje', 'návrh', 'a', 'realizaci', 'směru', 'progresivního', 'rozvoje.', 'Na', 'druhé', 'straně', 'rámec', 'stavu', 'vývoje', 'postavení', 'vyžadují', 'nalezení', 'jednoznačné', 'upřesnění', 'systému', 'masové', 'účasti.', 'Vzájemné', 'organizačních', 'autorit', 'stejně', 'jako', 'stabilní', 'kvantitativní', 'vzrůst', 'sféra', 'naší', 'aktivity', 'napomáhá', 'přípravě', 'nových', 'návrhů.', 'Stejně', 'tak', 'stálé,', 'informačně-propagandistické', 'zabezpečení', 'jednoznačně', 'předurčuje', 'implementaci', 'odpovídajících', 'podmínek', 'aktivizace.', 'Nesmíme', 'však', 'zapomínat,', 'že', 'konzultace', 'se', 'širokým', 'aktivem', 'vyzaduje', 'rozšiřování', 'logistických', 'prostředků', 'forem', 'působení.', 'Ideové', 'úvahy', 'nejvyššího', 'řádu', 'rovněž', 'rozvoj', 'struktur', 'přetváří', 'strukturu', 'vedení', 'dalších', 'směrů', 'Tímto', 'způsobem', 'komplexní', 'analýza', 'našich', 'možností', 'od', 'nás', 'analýzy', 'výchovy', 'pracovníků', 'aktuálním', 'potřebám.', 'Závažnost', 'těchto', 'problémů', 'je', 'natolik', 'zřejmá,', 'nový', 'model', 'organizační', 'činnosti', 'zvyšuje', 'potřebu', 'aplikace', 'modelu', 'Pestré', 'bohaté', 'zkušenosti', 'jasně', 'říkají,', 'další', 'různých', 'představuje', 'pozoruhodný', 'experiment', 'prověrky', 'možnosti', 'nasazení', 'veškerých', 'dostupných', 'prostředků.', 'Každodenní', 'praxe', 'nám', 'potvrzuje,', 'počátek', 've', 'značné', 'míře', 'podmiňuje', 'vytvoření', 'tvorby', 'zdrojů.']
Naproti tomu převod na slovník vrací prvky ve formě klíčů a hodnotami jsou jednotlivé čítače:
{'Počátek': 1, 'každodenní': 2, 'práce': 3, 'na': 2, 'poli': 2, 'formování': 2, 'pozice': 2, 'vyžaduje': 2, 'návrh': 1, 'a': 10, 'realizaci': 2, 'směru': 1, 'progresivního': 1, 'rozvoje.': 3, 'Na': 1, 'druhé': 1, 'straně': 1, 'rámec': 1, 'stavu': 1, 'vývoje': 1, 'postavení': 2, 'vyžadují': 1, 'nalezení': 1, 'jednoznačné': 1, 'upřesnění': 2, 'systému': 2, 'masové': 1, 'účasti.': 1, 'Vzájemné': 1, 'organizačních': 1, 'autorit': 1, 'stejně': 1, 'jako': 1, 'stabilní': 1, 'kvantitativní': 1, 'vzrůst': 1, 'sféra': 1, 'naší': 2, 'aktivity': 1, 'napomáhá': 1, 'přípravě': 1, 'nových': 2, 'návrhů.': 1, 'Stejně': 1, 'tak': 1, 'stálé,': 1, 'informačně-propagandistické': 1, 'zabezpečení': 1, 'jednoznačně': 1, 'předurčuje': 1, 'implementaci': 1, 'odpovídajících': 2, 'podmínek': 1, 'aktivizace.': 1, 'Nesmíme': 1, 'však': 1, 'zapomínat,': 1, 'že': 4, 'konzultace': 1, 'se': 1, 'širokým': 1, 'aktivem': 1, 'vyzaduje': 1, 'rozšiřování': 1, 'logistických': 1, 'prostředků': 1, 'forem': 2, 'působení.': 1, 'Ideové': 1, 'úvahy': 1, 'nejvyššího': 1, 'řádu': 1, 'rovněž': 1, 'rozvoj': 2, 'struktur': 1, 'přetváří': 1, 'strukturu': 1, 'vedení': 1, 'dalších': 1, 'směrů': 1, 'Tímto': 1, 'způsobem': 1, 'komplexní': 1, 'analýza': 1, 'našich': 1, 'možností': 1, 'od': 1, 'nás': 1, 'analýzy': 1, 'výchovy': 1, 'pracovníků': 1, 'aktuálním': 1, 'potřebám.': 1, 'Závažnost': 1, 'těchto': 1, 'problémů': 1, 'je': 1, 'natolik': 1, 'zřejmá,': 1, 'nový': 1, 'model': 1, 'organizační': 1, 'činnosti': 2, 'zvyšuje': 1, 'potřebu': 1, 'aplikace': 1, 'modelu': 1, 'Pestré': 1, 'bohaté': 1, 'zkušenosti': 1, 'jasně': 1, 'říkají,': 1, 'další': 1, 'různých': 1, 'představuje': 1, 'pozoruhodný': 1, 'experiment': 1, 'prověrky': 1, 'možnosti': 1, 'nasazení': 1, 'veškerých': 1, 'dostupných': 1, 'prostředků.': 1, 'Každodenní': 1, 'praxe': 1, 'nám': 1, 'potvrzuje,': 1, 'počátek': 1, 've': 1, 'značné': 1, 'míře': 1, 'podmiňuje': 1, 'vytvoření': 1, 'tvorby': 1, 'zdrojů.': 1}
8. Multimnožiny
Dalším typem kontejneru, se kterým se v dnešním článku seznámíme, jsou multimnožiny neboli multiset, popř. taktéž bag. Jedná se o kontejner, který nabízí podobné operace jako běžné množiny (sjednocení, průnik, diference, …), ovšem oproti klasickým množinám umožňuje, aby multimnožina obsahovala některý prvek vícekrát – není tedy zaručena unikátnost prvků. Mohlo by se zdát, že multimnožina je totéž, co již výše popsaný kontejner Counter, ale není tomu tak. Pokud do čítače vložíme dva prvky „foo“, bude výsledkem čítač obsahující „foo:2“, zatímco multimnožina bude obsahovat {„foo“, „foo“}.
9. Instalace balíčku multiset
Multimnožiny jsou implementovány v balíčku multiset, který je velmi malý a nemá žádné další tranzitivní závislosti:
$ pip3 install multiset
Průběh instalace (nainstaluje se jen několik kilobajtů závislostí):
Collecting multiset Downloading multiset-3.1.0-py2.py3-none-any.whl (11 kB) Installing collected packages: multiset Successfully installed multiset-3.1.0
10. Konstrukce kontejneru Multiset
Podobně jako v případě kontejneru typu Counter si nejdříve ukážeme, jakým způsobem se multimnožina konstruuje. V tom nejjednodušším případě se konstruktoru Multiset nepředá žádný parametr a multimnožina tedy bude prázdná:
from multiset import Multiset m = Multiset() print(m)
Výsledek:
{}
Multimnožině můžeme předat seznam, který dokonce (logicky) může obsahovat opakující se prvky:
from multiset import Multiset m = Multiset(["foo", "bar", "baz"]) print(m) m2 = Multiset(["foo", "foo", "foo", "bar", "bar", "baz"]) print(m2)
Nyní je z vypsaných zpráv patrné, že multimnožina skutečně může obsahovat opakující se prvky a tudíž prvky nejsou unikátní (což někdy může vadit, jindy ne):
{foo, bar, baz} {foo, foo, foo, bar, bar, baz}
Podobně můžeme konstruktoru multimnožiny předat n-tici, opět s možností opakování prvků:
from multiset import Multiset m = Multiset(("foo", "bar", "baz")) print(m) m2 = Multiset(("foo", "foo", "foo", "bar", "bar", "baz")) print(m2)
Výsledky budou v tomto případě totožné s předchozím demonstračním příkladem:
{foo, bar, baz} {foo, foo, foo, bar, bar, baz}
Konstrukce multimnožiny z běžné množiny (zde je tedy zaručeno, že se prvky nebudou opakovat, protože to běžná množina neumožňuje):
from multiset import Multiset m = Multiset({"foo", "bar", "baz"}) print(m)
Výsledek:
{foo, bar, baz}
11. Specifikace počtu shodných prvků při konstrukci multimnožiny
Pokud multimnožinu zkonstruujeme tak, že jí do konstruktoru předáme slovník, je tímto způsobem možné specifikovat opakování prvků v multimnožině:
from multiset import Multiset m = Multiset({"foo": 0, "bar": 1, "baz": 2, "baf": 3}) print(m)
V tomto případě bude výsledkem multimnožina, ve které nebude obsažen prvek „foo“, ale například prvek „baf“ zde bude naopak obsažen celkem třikrát:
{bar, baz, baz, baf, baf, baf}
12. Převod mezi kontejnerem Counter a multimnožinou
A pro úplnost si ukažme konstrukci multimnožiny z kontejneru Counter popsaného v předchozích kapitolách. Nejprve naplníme kontejner Counter a posléze ho předáme konstruktoru třídy Multiset:
from multiset import Multiset from collections import Counter c = Counter() sentences = """ Počátek každodenní práce na poli formování pozice vyžaduje návrh a realizaci směru progresivního rozvoje. Na druhé straně rámec stavu a vývoje postavení vyžadují nalezení a jednoznačné upřesnění systému masové účasti. Vzájemné postavení organizačních autorit stejně jako stabilní a kvantitativní vzrůst a sféra naší aktivity napomáhá přípravě a realizaci nových návrhů. Stejně tak stálé, informačně-propagandistické zabezpečení naší práce jednoznačně předurčuje implementaci odpovídajících podmínek aktivizace. Nesmíme však zapomínat, že konzultace se širokým aktivem vyzaduje rozšiřování logistických prostředků a forem působení. Ideové úvahy nejvyššího řádu a rovněž upřesnění a rozvoj struktur přetváří strukturu vedení dalších směrů rozvoje. Tímto způsobem komplexní analýza našich možností od nás vyžaduje analýzy systému výchovy pracovníků odpovídajících aktuálním potřebám. Závažnost těchto problémů je natolik zřejmá, že nový model organizační činnosti zvyšuje potřebu aplikace modelu rozvoje. Pestré a bohaté zkušenosti jasně říkají, že další rozvoj různých forem činnosti představuje pozoruhodný experiment prověrky možnosti nasazení veškerých dostupných prostředků. Každodenní praxe nám potvrzuje, že počátek každodenní práce na poli formování pozice ve značné míře podmiňuje vytvoření tvorby nových zdrojů. """ words = sentences.split() c.update(words) m = Multiset(c) print(m)
Výsledkem bude multimnožina s opakujícími se prvky. Na pořadí prvků ovšem v naprosté většině případů nezáleží:
{Počátek, každodenní, každodenní, práce, práce, práce, na, na, poli, poli, formování, formování, pozice, pozice, vyžaduje, vyžaduje, návrh, a, a, a, a, a, a, a, a, a, a, realizaci, realizaci, směru, progresivního, rozvoje., rozvoje., rozvoje., Na, druhé, straně, rámec, stavu, vývoje, postavení, postavení, vyžadují, nalezení, jednoznačné, upřesnění, upřesnění, systému, systému, masové, účasti., Vzájemné, organizačních, autorit, stejně, jako, stabilní, kvantitativní, vzrůst, sféra, naší, naší, aktivity, napomáhá, přípravě, nových, nových, návrhů., Stejně, tak, stálé,, informačně-propagandistické, zabezpečení, jednoznačně, předurčuje, implementaci, odpovídajících, odpovídajících, podmínek, aktivizace., Nesmíme, však, zapomínat,, že, že, že, že, konzultace, se, širokým, aktivem, vyzaduje, rozšiřování, logistických, prostředků, forem, forem, působení., Ideové, úvahy, nejvyššího, řádu, rovněž, rozvoj, rozvoj, struktur, přetváří, strukturu, vedení, dalších, směrů, Tímto, způsobem, komplexní, analýza, našich, možností, od, nás, analýzy, výchovy, pracovníků, aktuálním, potřebám., Závažnost, těchto, problémů, je, natolik, zřejmá,, nový, model, organizační, činnosti, činnosti, zvyšuje, potřebu, aplikace, modelu, Pestré, bohaté, zkušenosti, jasně, říkají,, další, různých, představuje, pozoruhodný, experiment, prověrky, možnosti, nasazení, veškerých, dostupných, prostředků., Každodenní, praxe, nám, potvrzuje,, počátek, ve, značné, míře, podmiňuje, vytvoření, tvorby, zdrojů.}
13. Spojení multimnožin, multimnožina vzniklá opakováním jiné multimnožiny
Multimnožiny je možné v případě potřeby spojit, a to opět s využitím přetíženého operátoru „+“, podobně jako u většiny již popsaných kontejnerů (s výjimkou klasických slovníků). Při spojení se pochopitelně berou v úvahu i opakující se prvky:
from multiset import Multiset m1 = Multiset(["foo", "bar", "baz", "baf", "xyzzy"]) print(m1) m2 = Multiset({"foo": 0, "bar": 1, "baz": 2, "baf": 3}) print(m2) m3 = m1 + m2 print(m3)
Po spuštění tohoto skriptu se nejprve vypíše obsah původních multimnožin a následně i výsledek jejich spojení:
{foo, bar, baz, baf, xyzzy} {bar, baz, baz, baf, baf, baf} {foo, bar, bar, baz, baz, baz, baf, baf, baf, baf, xyzzy}
Přetíženým operátorem * lze zajistit vytvoření nové multimnožiny stejně, jako bychom toho dosáhli opakovaným použitím operátoru +. Opět se pochopitelně berou v úvahu opakující se prvky (budou se opakovat minimálně n-krát):
from multiset import Multiset m1 = Multiset(["foo", "bar", "baz", "baf", "xyzzy"]) print(m1) m2 = m1 * 3 print(m2)
Opět platí, že se nejprve vypíše původní multimnožina a posléze multimnožina po aplikaci operace „opakování n-krát“:
{foo, bar, baz, baf, xyzzy} {foo, foo, foo, bar, bar, bar, baz, baz, baz, baf, baf, baf, xyzzy, xyzzy, xyzzy}
14. Operace update a combine
Operací (metodou) update lze zajistit přidání nového prvku či prvků do multimnožiny, a to i v případě, že takový prvek/prvky již v množině existují:
from multiset import Multiset m = Multiset({"foo": 0, "bar": 1, "baz": 2, "baf": 3}) print(m) m.update(["foo"]) print(m) m.update(["bar"]) print(m)
Povšimněte si, jak se postupně do multimnožiny přidávají další a další prvky:
{bar, baz, baz, baf, baf, baf} {bar, baz, baz, baf, baf, baf, foo} {bar, bar, baz, baz, baf, baf, baf, foo}
Naproti tomu metoda nazvaná combine dokáže zkombinovat více multimnožin a vytvořit multimnožinu novou. V našem konkrétním příkladu bude tedy nejpodstatnější rozdíl spočívat v tom, že combine vrací novou množinu, zatímco update modifikuje množinu původní:
from multiset import Multiset m = Multiset({"foo": 0, "bar": 1, "baz": 2, "baf": 3}) print(m) m2 = m.combine(["foo"]) print(m2) m3 = m.combine(["bar"]) print(m3) m4 = m.combine(["xyzzy"]) print(m4)
A takto vypadají multimnožiny m, m2, m3 a m4:
{bar, baz, baz, baf, baf, baf} {bar, baz, baz, baf, baf, baf, foo} {bar, bar, baz, baz, baf, baf, baf} {bar, baz, baz, baf, baf, baf, xyzzy}
15. Multimnožiny a multimnožinové operace
Až prozatím se multimnožiny vlastně chovaly podobně jako běžné seznamy. Ovšem navíc je nad nimi možné provádět „multimnožinové“ operace, což jsou obdoby klasických množinových operací sjednocení, průniku, diference a symetrické diference. Podívejme se nejdříve na případ, kdy multimnožiny obsahují pouze unikátní prvky:
from multiset import Multiset m1 = Multiset(["a", "b", "c", "d"]) m2 = Multiset(["c", "d", "e", "f"]) print(m1) print(m2) print(m1 | m2) print(m1 & m2) print(m1 - m2) print(m1 ^ m2)
Výsledky (s dopsanými poznámkami):
{a, b, c, d} ; m1 {c, d, e, f} ; m2 {a, b, c, d, e, f} ; sjednocení {c, d} ; průnik {a, b} ; diference {f, e, a, b} ; symetrická diference
A nyní si ukažme tyto operace nad multimnožinami, ve kterých se prvky opakují:
from multiset import Multiset m1 = Multiset(["a", "a", "b", "b", "c", "c", "d", "d"]) m2 = Multiset(["c", "c", "d", "d", "e", "e", "f", "f"]) print(m1) print(m2) print(m1 | m2) print(m1 & m2) print(m1 - m2) print(m1 ^ m2)
Výsledky s dopsanými poznámkami:
{a, a, b, b, c, c, d, d} ; m1 {c, c, d, d, e, e, f, f} ; m2 {a, a, b, b, c, c, d, d, e, e, f, f} ; sjednocení {c, c, d, d} ; průnik {a, a, b, b} ; diference {b, b, a, a, f, f, e, e} ; symetrická diference
16. Multislovníky
S multimnožinou do určité míry souvisí i další nestandardní typ kontejneru, který se nazývá multislovník (multidict). Tento kontejner se liší od běžných slovníků, v nichž je zaručena jednoznačnost klíčů, což znamená, že klíč lze použít ve formě selektoru jediné hodnoty (popř. samozřejmě klíč, resp. dvojice klíč+hodnota vůbec nemusí ve slovníku existovat). V multislovnících je tomu ovšem jinak, protože může existovat větší množství dvojic klíč+hodnota se stejným klíčem.
17. Instalace balíčku multidict
Multislovník je implementovaný v balíčku nazvaném multidict, který je opět nutné nejdříve nainstalovat:
$ pip3 install multidict
Tento balíček opět nemá žádné další závislosti, což je patrné z následujícího výpisu průběhu instalace:
Defaulting to user installation because normal site-packages is not writeable Collecting multidict Downloading multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (128 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 128.7/128.7 kB 1.4 MB/s eta 0:00:00 Installing collected packages: multidict Successfully installed multidict-6.0.5
$ pip3 install python-bidi
18. Základní operace s multislovníky
Multislovníky se konstruují podobně jako běžné slovníky, ovšem musíme explicitně volat konstruktor MultiDict (neexistuje tedy žádná speciální syntaxe pro multislovníky, což ale nebude příliš překvapivé). Příkladem může být konstrukce multislovníku z běžného slovníku. Dále jsou k dispozici běžné operace přidání prvku, změnu prvku a vypazání prvky:
from multidict import MultiDict d = MultiDict({"id": 1, "name": "Eda", "surname": "Wasserfall"}) print(d) print(d["name"]) d["hra"] = "Svestka" print(d)
A takto vypadá výsledek běhu tohoto skriptu:
<MultiDict('id': 1, 'name': 'Eda', 'surname': 'Wasserfall')> Eda <MultiDict('id': 1, 'name': 'Eda', 'surname': 'Wasserfall', 'hra': 'Svestka')>
Při pokusu o vymazání neexistujícího prvku se vyhodí výjimka:
from multidict import MultiDict d = MultiDict({"id": 1, "name": "Eda", "surname": "Wasserfall"}) del d["id"] del d["foo"] del d["bar"] print(d)
Další operace, zejména ty, které jsou specifické právě pro multislovníky, si popíšeme v navazujícím článku.
19. Repositář s demonstračními příklady
Zdrojové kódy všech prozatím popsaných demonstračních příkladů určených pro programovací jazyk Python 3 byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. Odkazy na jednotlivé příklady jsou vypsány v následující tabulce:
20. Odkazy na Internetu
- collections – Container datatypes
https://docs.python.org/3/library/collections.html - Counting With Python's Counter (Overview) – Real Python
https://realpython.com/lessons/counting-python-counter-overview/ - Python Counter: Learn the Easiest Way of Counting Objects in Python
https://towardsdatascience.com/python-counter-learn-the-easiest-way-of-counting-objects-in-python-9165d15ea893 - Balíček multidict na PyPi
https://pypi.org/project/multidict/ - Balíček multiset na PyPi
https://pypi.org/project/multiset/ - Repositář balíčku multidict
https://github.com/aio-libs/multidict - Repositář balíčku bidict
https://github.com/jab/bidict - Dokumentace k balíčku bidict
https://bidict.readthedocs.io/en/main/ - Repositář balíčku DottedDict
https://github.com/carlosescri/DottedDict - Repositář balíčku Box
https://github.com/cdgriffith/Box - Wiki (dokumentace) balíčku Box
https://github.com/cdgriffith/Box/wiki - Persistent data structure
https://en.wikipedia.org/wiki/Persistent_data_structure - Collections (Python)
https://docs.python.org/3/library/collections.abc.html - Seriál Programovací jazyk Lua
https://www.root.cz/serialy/programovaci-jazyk-lua/ - Operátory a asociativní pole v jazyku Lua
https://www.root.cz/clanky/operatory-a-asociativni-pole-v-jazyku-lua/ - Python MultiDict Example: Map a Key to Multiple Values
https://howtodoinjava.com/python-datatypes/python-multidict-examples/ - Immutable object
https://en.wikipedia.org/wiki/Immutable_object - pyrsistent na PyPi
https://pypi.org/project/pyrsistent/ - pyrsistent na GitHubu
https://github.com/tobgu/pyrsistent - Dokumentace knihovny pyrsistent
https://pyrsistent.readthedocs.io/en/latest/index.html - pyrthon na GitHubu
https://github.com/tobgu/pyrthon/ - Mori na GitHubu
https://github.com/swannodette/mori - Mori: popis API (dokumentace)
http://swannodette.github.io/mori/ - Mori: Benchmarking
https://github.com/swannodette/mori/wiki/Benchmarking - Functional data structures in JavaScript with Mori
http://sitr.us/2013/11/04/functional-data-structures.html - Immutable.js
https://facebook.github.io/immutable-js/ - Understanding Clojure's Persistent Vectors, pt. 1
http://hypirion.com/musings/understanding-persistent-vector-pt-1 - Hash array mapped trie (Wikipedia)
https://en.wikipedia.org/wiki/Hash_array_mapped_trie - Java theory and practice: To mutate or not to mutate?
http://www.ibm.com/developerworks/java/library/j-jtp02183/index.html - Efficient persistent (immutable) data structures
https://persistent.codeplex.com/ - Clojure (Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure