Kontejnery v Pythonu: zdaleka nejde jen o n-tice, seznamy, množiny a slovníky (2)

2. 5. 2024
Doba čtení: 29 minut

Sdílet

Autor: Root.cz s využitím DALL-E
Popíšeme si dvojici potenciálně velmi užitečných a přitom méně známých kontejnerů: Counter a multimnožiny. Taktéž se zmíníme o multislovníku, s nímž se taktéž můžeme v praxi setkat.

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

8. Multimnožiny

9. Instalace balíčku multiset

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

14. Operace update a combine

15. Multimnožiny a multimnožinové operace

16. Multislovníky

17. Instalace balíčku multidict

18. Základní operace s multislovníky

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

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.

Poznámka: v některých zdrojových kódech se můžeme setkat s tím, že se namísto kontejneru Counter používá běžný slovník. To ovšem nemusí být nejvhodnější řešení, protože už jen tím, že ve skriptu použijeme Counter se potenciálním čtenářům dává jasně najevo, jaká bude sémantika právě vytvořeného kontejneru.

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“}.

Poznámka: opět se poměrně často můžeme setkat s tím, že se ve zdrojových kódech prakticky znovuimplementují multimnožiny (resp. jejich vlastnosti a operace) a to s využitím klasických seznamů. Ze sémantického hlediska je však lepší použít přímo typ multiset.

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}
Poznámka: tato operace modifikuje původní množinu.

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:

bitcoin školení listopad 24

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:

# Demonstrační příklad Stručný popis příkladu Cesta
1 std_tuple01.py konstrukce n-tic https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_tuple01.py
2 std_tuple02.py spojování n-tic operátorem + https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_tuple02.py
3 std_tuple03.py opakování obsahu n-tice operátorem * https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_tuple03.py
4 std_tuple04.py operátor in a n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_tuple04.py
5 std_tuple05.py generátorová notace a n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_tuple05.py
       
6 std_list01.py konstrukce seznamů https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_list01.py
7 std_list02.py spojování seznamů operátorem + https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_list02.py
8 std_list03.py opakování obsahu seznamu operátorem * https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_list03.py
9 std_list04.py řazení prvků seznamu: funkcionální a imperativní přístup https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_list04.py
10 std_list05.py otočení prvků v seznamu https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_list05.py
11 std_list06.py generátorová notace seznamů https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_list06.py
       
12 std_set01.py konstrukce množin https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_set01.py
13 std_set02.py operace nad množinami https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_set02.py
14 std_set03.py operace nad množinami https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_set03.py
15 std_set04.py rozdíl mezi operacemi discard a remove https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_set04.py
16 std_set05.py generátorová notace množin https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_set05.py
       
17 std_dict01.py konstrukce slovníků https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_dict01.py
18 std_dict02.py selektory, operace del https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_dict02.py
19 std_dict03.py chování v případě, že mazaný prvek ve slovníku neexistuje https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_dict03.py
20 std_dict04.py spojení dvou slovníků https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_dict04.py
21 std_dict05.py generátorová notace slovníků https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_dict05.py
       
22 std_deque01.py konstrukce obousměrné fronty ze seznamu https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque01.py
23 std_deque02.py konstrukce obousměrné fronty z n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque02.py
24 std_deque03.py konstrukce obousměrné fronty z množiny https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque03.py
25 std_deque04.py operace append https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque04.py
26 std_deque05.py operace appendleft https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque05.py
27 std_deque06.py operace insert https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque06.py
28 std_deque07.py operace pop https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque07.py
29 std_deque08.py operace popleft https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque08.py
30 std_deque09.py otočení prvků ve frontě https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque09.py
31 std_deque10.py rotace prvků ve frontě https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/std_deque10.py
       
32 box01.py konstrukce boxu https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box01.py
33 box02.py přístup k prvkům boxu přes klíč i atribut https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box02.py
34 box03.py chování při pokusu o přístup k neexistující hodnotě přes klíč https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box03.py
35 box04.py chování při pokusu o přístup k neexistující hodnotě přes atribut https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box04.py
36 box05.py chování při použití klíčů, které nejsou platnými názvy atributů v Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box05.py
37 box06.py náhrada nekorektních názvů klíčů https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box06.py
38 box07.py explicitní prefix u nekorektních názvů klíčů https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box07.py
39 box08.py načtení datového souboru, přístup k prvkům přes klíče i atributy https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box08.py
40 box09.py využití klíče s tečkami https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box09.py
41 box10.py iterace přes prvky uložené do boxu https://github.com/tisnik/most-popular-python-libs/blob/master/containers/box10.py
       
42 openapi.json datový soubor používaný v některých demonstračních příkladech https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/openapi.json
       
43 counter01.py konstrukce prázdného kontejneru Counter https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter01.py
44 counter02.py konstrukce kontejneru Counter ze seznamu https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter02.py
45 counter03.py konstrukce kontejneru Counter z n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter03.py
46 counter04.py konstrukce kontejneru Counter z množiny https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter04.py
47 counter05.py konstrukce kontejneru Counter ze slovníku https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter05.py
48 counter06.py spojení dvou kontejnerů Counter https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter06.py
49 counter07.py rozdíl čítačů ze dvou kontejnerů Counter https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter07.py
50 counter08.py výpočet frekvence znaků v textu, využití programové smyčky https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter08.py
51 counter09.py výpočet frekvence slov v textu, využití programové smyčky https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter09.py
52 counter10.py převod kontejneru Counter na seznam a slovník https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter10.py
53 counter11.py výpočet frekvence slov v textu, zjednodušená varianta https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/counter11.py
       
54 multiset01.py konstrukce prázdné multimnožiny https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset01.py
55 multiset02.py konstrukce multimnožiny ze seznamu https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset02.py
56 multiset03.py konstrukce multimnožiny z n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset03.py
57 multiset04.py konstrukce multimnožiny ze standardní množiny https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset04.py
58 multiset05.py konstrukce multimnožiny ze slovníku se stanovením počtu prvků https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset05.py
59 multiset06.py spojení multimnožin https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset06.py
60 multiset07.py operace update pro modifaci multimnožiny https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset07.py
61 multiset08.py operace combine pro kombinaci většího množství multimnožin https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset08.py
62 multiset09.py multimnožinové operace v případě, že multimnožiny obsahují unikátní prvky https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset09.py
63 multiset10.py multimnožinové operace v případě, že multimnožiny obsahují opakující se prvky https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset10.py
64 multiset11.py multimnožina vzniklá opakováním jiné multimnožiny https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset11.py
65 multiset12.py multimnožina zkonstruovaná z kontejneru Counter https://github.com/tisnik/most-popular-python-libs/blob/master/container­s/multiset12.py

20. Odkazy na Internetu

  1. collections – Container datatypes
    https://docs.python.org/3/li­brary/collections.html
  2. Counting With Python's Counter (Overview) – Real Python
    https://realpython.com/les­sons/counting-python-counter-overview/
  3. 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
  4. Balíček multidict na PyPi
    https://pypi.org/project/multidict/
  5. Balíček multiset na PyPi
    https://pypi.org/project/multiset/
  6. Repositář balíčku multidict
    https://github.com/aio-libs/multidict
  7. Repositář balíčku bidict
    https://github.com/jab/bidict
  8. Dokumentace k balíčku bidict
    https://bidict.readthedoc­s.io/en/main/
  9. Repositář balíčku DottedDict
    https://github.com/carloses­cri/DottedDict
  10. Repositář balíčku Box
    https://github.com/cdgriffith/Box
  11. Wiki (dokumentace) balíčku Box
    https://github.com/cdgrif­fith/Box/wiki
  12. Persistent data structure
    https://en.wikipedia.org/wi­ki/Persistent_data_structu­re
  13. Collections (Python)
    https://docs.python.org/3/li­brary/collections.abc.html
  14. Seriál Programovací jazyk Lua
    https://www.root.cz/seria­ly/programovaci-jazyk-lua/
  15. Operátory a asociativní pole v jazyku Lua
    https://www.root.cz/clanky/operatory-a-asociativni-pole-v-jazyku-lua/
  16. Python MultiDict Example: Map a Key to Multiple Values
    https://howtodoinjava.com/python-datatypes/python-multidict-examples/
  17. Immutable object
    https://en.wikipedia.org/wi­ki/Immutable_object
  18. pyrsistent na PyPi
    https://pypi.org/project/pyrsistent/
  19. pyrsistent na GitHubu
    https://github.com/tobgu/pyrsistent
  20. Dokumentace knihovny pyrsistent
    https://pyrsistent.readthe­docs.io/en/latest/index.html
  21. pyrthon na GitHubu
    https://github.com/tobgu/pyrthon/
  22. Mori na GitHubu
    https://github.com/swannodette/mori
  23. Mori: popis API (dokumentace)
    http://swannodette.github.io/mori/
  24. Mori: Benchmarking
    https://github.com/swanno­dette/mori/wiki/Benchmarking
  25. Functional data structures in JavaScript with Mori
    http://sitr.us/2013/11/04/functional-data-structures.html
  26. Immutable.js
    https://facebook.github.io/immutable-js/
  27. Understanding Clojure's Persistent Vectors, pt. 1
    http://hypirion.com/musin­gs/understanding-persistent-vector-pt-1
  28. Hash array mapped trie (Wikipedia)
    https://en.wikipedia.org/wi­ki/Hash_array_mapped_trie
  29. Java theory and practice: To mutate or not to mutate?
    http://www.ibm.com/develo­perworks/java/library/j-jtp02183/index.html
  30. Efficient persistent (immutable) data structures
    https://persistent.codeplex.com/
  31. Clojure (Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  32. Clojure (Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
ikonka

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.