---
# System prepended metadata

title: Rječnici i skupovi
tags: [Programiranje koristeći Python]

---

Rječnici i skupovi
==================

Rad sa podacima u programskim jezicima temelji se na njihovom čuvanju u varijablama različitih tipova. Brojčani podaci, logičke vrijednosti i druge vrste podataka pohranjuju se u odgovarajuće tipove, pružajući osnovnu strukturu za rad sa informacijama. Kada je potrebno pohraniti više elemenata u jednu varijablu, tradicionalni pristup bio je korištenje listi. 

Iako liste nude brz i praktičan način za rad sa nizovima podataka, one nisu idealno rješenje za organizaciju složenijih informacija. Njihova ograničenja, poput nepostojanja direktne veze između elemenata ili sporo pretraživanje, dovela su do razvoja naprednijih struktura podataka. 

Rječnici i skupovi su među najvažnijim strukturama podataka koje omogućavaju efikasnu organizaciju i upravljanje kompleksnim informacijama. Zahvaljujući njihovim osobinama, često se koriste u situacijama gdje je ključno brzo dohvatiti podatke ili obraditi velike količine informacija.

# Rječnici

Rječnici predstavljaju kolekcije u Pythonu koje organizuju podatke u obliku **ključ-vrijednost** parova. Svaki ključ mora biti jedinstven i koristi se za brzo pronalaženje pripadajuće vrijednosti. Ova struktura omogućava efikasnu organizaciju i pristup podacima, naročito kada je potrebno brzo dohvatiti specifične informacije na osnovu nekog identifikatora.

Primarna svrha rječnika je organizacija i efikasno pretraživanje podataka. Ova struktura je idealna za reprezentaciju objekata s atributima, gdje ključevi predstavljaju nazive atributa, a vrijednosti njihove odgovarajuće vrijednosti. U primjeru ispod, razmotren je opis Bosne i Hercegovine. Ključ-vrijednost parovi omogućavaju da se ključni atributi države jasno definišu i da im se jednostavno pristupi.

```python=
bih = {
    "naziv": "Bosna i Hercegovina",
    "glavni_grad": "Sarajevo",
    "kontinent": "Evropa",
    "povrsina_km2": 51197,
    "stanovnistvo": 3280819,
    "sluzbeni_jezici": ["bosanski", "hrvatski", "srpski"],
    "valuta": "Konvertibilna marka (BAM)",
    "susjedne_drzave": ["Hrvatska", "Srbija", "Crna Gora"],
    "pozivni_broj": "+387"
}
print(bih)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{'naziv': 'Bosna i Hercegovina', 'glavni_grad': 'Sarajevo', 'kontinent': 'Evropa', 'povrsina_km2': 51197, 'stanovnistvo': 3280819, 'sluzbeni_jezici': ['bosanski', 'hrvatski', 'srpski'], 'valuta': 'Konvertibilna marka (BAM)', 'susjedne_drzave': ['Hrvatska', 'Srbija', 'Crna Gora'], 'pozivni_broj': '+387'}
</pre>

Ovakva struktura omogućava jednostavan pristup bilo kojem atributu rječnika. Ispod je primjer u kojem se ispisuje podatak o glavnom gradu.

```python=
glavni_grad = bih["glavni_grad"]
print(f"Glavni grad Bosne i Hercegovine je {glavni_grad}.")
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Glavni grad Bosne i Hercegovine je Sarajevo.
</pre>


## Poređenje sa listama
Korištenje listi za pohranu kompleksnijih podataka često zahtijeva pristup elementima putem indeksa, što može biti nepraktično i otežava čitljivost koda. Na primjer, ako bi podaci o Bosni i Hercegovini bili pohranjeni u listi, izgledali bi ovako:

```python=
bih_lista = [
    "Bosna i Hercegovina",  # naziv
    "Sarajevo",             # glavni_grad
    "Evropa",               # kontinent
    51197,                  # povrsina_km2
    3280819,                # stanovnistvo
    ["bosanski", "hrvatski", "srpski"],  # sluzbeni_jezici
    "Konvertibilna marka (BAM)",        # valuta
    ["Hrvatska", "Srbija", "Crna Gora"], # susjedne_drzave
    "+387"                  # pozivni_broj
]
```

Pristup informacijama u ovom slučaju zahtijeva poznavanje tačnog indeksa svakog elementa.

```python=
glavni_grad = bih_lista[1]
print(f"Glavni grad Bosne i Hercegovine je {glavni_grad}.")
```

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Glavni grad Bosne i Hercegovine je Sarajevo.
</pre>

Ovakav pristup je funkcionalan, ali manje intuitivan, posebno kada se radi o većim ili kompleksnijim podacima. Promjena redoslijeda podataka unutar liste ili dodavanje novog podatka, može dovesti do grešaka u kodu, jer su svi pristupi bazirani na indeksima.

S druge strane, rječnici omogućavaju direktan pristup podacima putem njihovih naziva (ključeva), što kod čini čitljivijim i manje podložnim greškama.

Pored čitljivosti, rječnici pružaju dodatne mogućnosti, poput provjere prisustva određenog ključa, dodavanja novih atributa ili ažuriranja postojećih, što ih čini fleksibilnijim za rad sa strukturiranim podacima.

## Dodatni primjeri upotrebe rječnika

Rječnici se koriste u brojnim praktičnim situacijama gdje je potrebna jasna veza između identifikatora i njihovih vrijednosti. U nastavku će biti navedeno nekoliko primjera.

1. **Meni restorana**:
   ```python=
   meni = {
       "Burek": 18.5,
       "Sirnica": 13.0,
       "Zeljanica": 13.0
   }
   print(f"Cijena bureka je {meni['Burek']} KM.")
   ```

2. **Rječnik jezika**:
   ```python=
   rijeci = {
       "kuća": "house",
       "stablo": "tree",
       "voda": "water"
   }
   print(f"Riječ 'kuća' na engleskom jeziku je '{rijeci['kuća']}'.")
   ```

3. **Informacije o korisnicima**:
   ```python=
   korisnik = {
       "ime": "Elmedin",
       "prezime": "Selmanović",
       "email": "elmedins@nekimail.com"

   }
   print(f"Korisnik {korisnik['ime']} {korisnik['prezime']} ima e-mail {korisnik['email']}.")
   ```

4. **Statistika sportskih timova**:
   ```python=
   tim = {
       "ime": "Real Madrid",
       "pobjede": 29,
       "neriješeno": 3,
       "porazi": 0
   }
   print(f"{tim['ime']} ima ukupno {tim['pobjede']} pobjeda.")
   ```

Osim navedenih primjera, rječnici pronalaze primjenu u različitim oblastima programiranja i svakodnevnog rada sa podacima. Njihova fleksibilnost omogućava organizaciju informacija u raznim kontekstima, od kataloga proizvoda i podataka o vozilima, preko rasporeda predavanja, pa sve do statistika korištenja aplikacija.


## Ključ-vrijednost

Rječnici čuvaju podatke u formatu `ključ: vrijednost`, gdje svaki ključ mora biti **jedinstven** i **nepromjenjiv**, dok vrijednosti mogu biti bilo koji tip podataka, uključujući liste, rječnike, pa čak i funkcije. Ova struktura omogućava efikasan način za organizaciju i pretraživanje podataka, što ih čini jednim od najvažnijih alata u programiranju. Neke od najvažnijih karakteristika navedene su ispod.

- **Ključevi moraju biti jedinstveni**: Nema dupliciranih ključeva u rječniku, što osigurava konzistentnost podataka.
- **Ključevi moraju biti nepromjenjivi**: Tipovi podataka kao što su stringovi, brojevi ili tuple se mogu koristiti za ključeve, dok liste ili rječnici ne mogu, jer su promjenjivi.
- **Vrijednosti su fleksibilne**: Vrijednosti mogu biti bilo kojeg tipa, što omogućava čuvanje složenih struktura podataka unutar jednog rječnika.

:::info
### Zašto su rječnici efikasni?

Rječnici su izuzetno efikasni zahvaljujući načinu na koji organizuju podatke. Ključna osobina rječnika je način čuvanja podataka u formatu **ključ-vrijednost**, gdje se koriste specijalne matematičke funkcije, poznate kao **hash funkcije**, za organizaciju i brzo pronalaženje informacija. Hash funkcija pretvara ključ u broj koji se koristi za određivanje lokacije vrijednosti u memoriji, čineći pretragu brzom i jednostavnom.

Kroz korištenje rječnika, dohvaćanje vrijednosti pomoću ključa traje približno isto vrijeme, bez obzira na to koliko podataka rječnik sadrži i koji se podatak dohvaća. Ovo se naziva **konstantna vremenska složenost** i u teoriji kompleksnosti se označava kao **O(1)**. U poređenju s listama, gdje je potrebno proći kroz elemente redom dok se ne pronađe tražena informacija (što može trajati duže kako lista raste, tj. **O(n)**), rječnici su znatno brži za ovakve operacije.

Razlika se može jednostavno objasniti primjerom: lista od milion elemenata u kojoj se traži određeni broj zahtijeva provjeru svakog broja redom dok se traženi broj ne pronađe, što može potrajati. Kod rječnika, zahvaljujući primjeni hash funkcije, traženi podatak se odmah pronalazi, bez potrebe za redoslijednim pretraživanjem.

Ova efikasnost čini rječnike idealnim za aplikacije gdje je brzina pristupa podacima ključna, poput upravljanja bazama podataka, obrada velikih količina informacija.
:::


## Rad sa rječnicima

Rječnici su već predstavljeni kroz primjer rječnika `bih` koji opisuje državu Bosnu i Hercegovinu. U nastavku će biti prikazano kako se koriste osnovne operacije sa rječnicima, kao što su pristup podacima, dodavanje i ažuriranje, brisanje, te iteracija kroz rječnik.

### Pristup podacima putem ključa

Kako je ranije prikazano, vrijednosti u rječniku se dohvaćaju korištenjem pripadajućih ključeva. Na primjer, pristupanje podatku o glavnom gradu u rječniku `bih` radi se kao u primjeru ispod.

```python=
glavni_grad = bih["glavni_grad"]
print(f"Glavni grad je {glavni_grad}.")
```

Sličan postupak se primjenjuje za dohvaćanje drugih podataka, poput jezika ili broja stanovnika, bez obzira na njihov tip.

```python=
# Dohvaćanje jezika
jezici = ", ".join(bih["sluzbeni_jezici"])
print(f"Službeni jezici su: {jezici}.")
```

### Dodavanje i ažuriranje podataka

Jedna od važnih karakteristika rječnika je svakako mogućnost dodavanja i ažuriranja podataka. Dodavanje i ažuriranje podataka se radi na sličan način, gdje se jednostavno određenom ključu dodijeli nova vrijednost. Ukoliko ključ ne postoji od ranije, rječnik će biti proširen. Ukoliko ključ postoji, vrijednost se ažurira.

```python=
# Dodavanje nove informacije
bih["turisticka_atrakcija"] = "Stari most u Mostaru"

# Ažuriranje postojećeg podatka
bih["stanovnistvo"] = 3300000
```

Dodavanjem ili ažuriranjem podataka, rječnik se jednostavno proširuje ili prilagođava novim informacijama.

### Brisanje podataka

Podaci se uklanjaju korištenjem ključeva ili metodom `pop()`.

```python=
# Brisanje koristeći ključ
del bih["turisticka_atrakcija"]

# Brisanje koristeći pop
turisticka_atrakcija = bih.pop("turisticka_atrakcija")
```

Metoda `pop()` omogućava uklanjanje elementa i vraćanje njegove vrijednosti.

### Broj elemenata

Za rječnike se koristi funkcija `len()` koja vraća ukupan broj elemeanta u rječniku.

```python=
print(len(bih))
```

### Iteracija kroz rječnik

Iteracija kroz rječnik omogućava pregled svih podataka, bilo da se radi samo o ključevima, vrijednostima ili o ključevima i vrijednostima zajedno. Python nudi metode `keys()`, `values()`, i `items()` koje se koriste za različite vrste iteracija, čime se omogućava fleksibilan i jednostavan rad s podacima.

#### Iteracija kroz ključeve

Metoda `keys()` se koristi za dohvaćanje svih ključeva rječnika. Ključevi se iteriraju redom kojim su pohranjeni u rječniku. Ovo je korisno kada je potrebno raditi samo sa identifikatorima podataka, a ne i sa njihovim vrijednostima.

```python=
for kljuc in bih.keys():
    print(f"Ključ: {kljuc}")
```

Rezultat izvršavanja naveden je ispod.
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Ključ: naziv 
Ključ: glavni_grad 
Ključ: kontinent 
Ključ: povrsina_km2 
Ključ: stanovnistvo 
Ključ: sluzbeni_jezici 
Ključ: valuta 
Ključ: susjedne_drzave 
Ključ: pozivni_broj 
</pre>

#### Iteracija kroz vrijednosti

Metoda `values()` omogućava prolazak kroz sve vrijednosti rječnika, bez obzira na njihove pripadajuće ključeve. Ovo je korisno kada su relevantne samo informacije (vrijednosti), a ne i njihovi identifikatori.

```python=
for vrijednost in bih.values():
    print(f"Vrijednost: {vrijednost}")
```

Rezultat izvršavanja naveden je ispod.

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Vrijednost: Bosna i Hercegovina 
Vrijednost: Sarajevo 
Vrijednost: Evropa 
Vrijednost: 51197 
Vrijednost: 3300000
Vrijednost: ['bosanski', 'hrvatski', 'srpski'] 
Vrijednost: Konvertibilna marka (BAM) 
Vrijednost: ['Hrvatska', 'Srbija', 'Crna Gora'] 
Vrijednost: +387 
</pre>


#### Iteracija kroz ključeve i vrijednosti

Metoda `items()` omogućava iteraciju kroz **ključeve i vrijednosti istovremeno**, što je vrlo praktično kada je potrebno raditi s oba podatka u paru. Svaka iteracija vraća tuple `(ključ, vrijednost)`.

```python=
for kljuc, vrijednost in bih.items():
    print(f"{kljuc}: {vrijednost}")
```

Rezultat izvršavanja naveden je ispod.

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
naziv: Bosna i Hercegovina
glavni_grad: Sarajevo 
kontinent: Evropa 
povrsina_km2: 51197 
stanovnistvo: 3300000 
sluzbeni_jezici: ['bosanski', 'hrvatski', 'srpski']
valuta: Konvertibilna marka (BAM) 
susjedne_drzave: ['Hrvatska', 'Srbija', 'Crna Gora']
pozivni_broj: +387 </pre>


#### Šta rade metode `keys()`, `values()`, i `items()`?

- **`keys()`**: Vraća listu svih ključeva rječnika.  
  - Koristi se kada su potrebni samo ključevi, npr. za provjeru postojanja određenog ključa.
  - Može se iterirati direktno kroz rječnik (`for kljuc in bih`), ali `keys()` čini namjeru jasnijom.

- **`values()`**: Vraća sve vrijednosti u rječniku.  
  - Koristi se kada se analiziraju podaci bez obzira na njihove ključeve.

- **`items()`**: Vraća sve parove `(ključ, vrijednost)` u obliku tuple-a.  
  - Koristi se kada je potreban rad sa cijelim rječnikom, omogućavajući pristup i ključu i pripadajućoj vrijednosti u jednoj iteraciji.


Ove metode omogućavaju precizno kontrolisanje načina iteracije kroz rječnik. Ovo je ključno za obradu podataka kada je potrebno filtrirati, transformisati ili analizirati određene elemente rječnika, jer se može iterirati samo kroz ono što je relevantno (ključeve, vrijednosti, ili oba). 

:::info
**Napomena:** Sve tri metode vraćaju posebne objekte koji su *iterabilni*, ali nisu prave liste. Ako je potrebna lista, može se koristiti funkcija `list()` da se objekti konvertuju. Na primjer:
```python=
kljucevi = list(bih.keys())
vrijednosti = list(bih.values())
```
:::

### Kopiranje rječnika
Prilikom rada sa rječnicima, često je potrebno kreirati njihovu kopiju kako bi se očuvao originalni skup podataka. U Pythonu, rječnici se mogu kopirati na nekoliko načina, pri čemu je važno razumjeti razliku između **plitkog** (eng. *shallow copy*) i **dubokog kopiranja** (eng. *deep copy*).

#### Plitko kopiranje (`copy()`)  

Plitko kopiranje stvara novu instancu rječnika s identičnim ključevima i vrijednostima, ali **ne kopira** složene objekte (npr. liste, drugi rječnici) unutar rječnika. Umjesto toga, referenca na iste objekte se prenosi u novi rječnik.  

```python=  
original = {  
    "ime": "Student",  
    "ocjene": [8, 9, 10]  
}  

kopija = original.copy()  

# Ažuriranje kopije
kopija["ocjene"].append(7)  

print(f"Original: {original}")  
print(f"Kopija: {kopija}")  
```  
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Original: {'ime': 'Student', 'ocjene': [8, 9, 10, 7]} 
Kopija: {'ime': 'Student', 'ocjene': [8, 9, 10, 7]}  
</pre>  

Iako je kreirana kopija rječnika `original`, obje verzije dijele istu listu `ocjene`. Promjena u kopiji automatski mijenja i originalni rječnik, što može dovesti do neočekivanih rezultata.  

#### Duboko kopiranje (`deepcopy()`) 

Duboko kopiranje osigurava da se **svi objekti** unutar rječnika rekreiraju i dodijele novoj instanci. Time se sprječava dijeljenje referenci između originala i kopije. Za duboko kopiranje koristi se modul `copy`.  

```python=  
import copy  

original = {  
    "ime": "Student",  
    "ocjene": [8, 9, 10]  
}  

duboka_kopija = copy.deepcopy(original)  

# Ažuriranje kopije
duboka_kopija["ocjene"].append(7)  

print(f"Original: {original}")  
print(f"Kopija: {duboka_kopija}")  
```  
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Original: {'ime': 'Student', 'ocjene': [8, 9, 10]}  
Kopija: {'ime': 'Student', 'ocjene': [8, 9, 10, 7]}  
</pre>  


Korištenjem `deepcopy()`, lista `ocjene` u `duboka_kopija` postaje **nova instanca**. Promjena podataka u kopiji ne utiče na original, čime se postiže potpuna nezavisnost između dva rječnika.  

#### Kopiranje rječnika sa `dict()`  

Rječnici se mogu kopirati i korištenjem funkcije `dict()`, koja funkcioniše slično kao `copy()`.  

```python=  
kopija = dict(original)  
print(kopija)  
```  

Ova metoda također kreira **plitku kopiju** rječnika.  

### Kada koristiti plitko, a kada duboko kopiranje?  

- **Plitko kopiranje**:  
   - Kada rječnik sadrži **samo jednostavne tipove podataka** (stringove, brojeve, booleane).  
   - Kada nije važno ako se složeni objekti (npr. liste) dijele između originala i kopije.  

- **Duboko kopiranje**:  
   - Kada rječnik sadrži **složene objekte** poput listi, drugih rječnika ili klasa.  
   - Kada je potrebno osigurati da izmjene u kopiji **ne utiču na original**.  


## Prednosti rječnika

Kako je ranije navedeno, rječnici u Pythonu nude brojne prednosti koje ih čine korisnim i učinkovitim strukturama podataka u programiranju. Njihova efikasnost dolazi iz jedinstvenog načina organizacije podataka kroz ključ-vrijednost parove. U nastavku su navedene glavne prednosti korištenja rječnika:

1. **Brzina pristupa podacima**  
   Zbog koncepta pohrane i pretraživanja podataka, rječnici direktno pronalaze traženi ključ. Ova metoda čini rječnike idealnim za scenarije u kojima su brzina i učestalost pretraživanja ključni faktori.

2. **Jednostavna organizacija podataka**  
   Korištenjem ključ-vrijednost parova, rječnici omogućavaju jasno mapiranje između ključeva i pripadajućih vrijednosti.

3. **Fleksibilnost vrijednosti**  
   Vrijednosti u rječnicima mogu biti bilo kojeg tipa podataka – od brojeva i stringova, do listi, drugih rječnika ili čak složenih objekata. Ovo omogućava da se rječnici koriste za pohranjivanje složenih i hijerarhijski organizovanih podataka.

4. **Jednostavno ažuriranje podataka**  
   Rječnici omogućavaju lako dodavanje, mijenjanje ili brisanje podataka. Dodavanje nove vrijednosti ili ažuriranje postojećeg ključa zahtijeva samo jedan jednostavan korak, što ih čini praktičnim za dinamične aplikacije.

5. **Jedinstvenost ključeva**  
   Ključevi u rječnicima moraju biti jedinstveni, što eliminiše mogućnost dupliciranja i pomaže u održavanju integriteta podataka. Ova karakteristika olakšava rad s velikim količinama podataka i smanjuje greške u programiranju.

6. **Optimizacija memorije**  
   Python rječnici su visoko optimizirani za čuvanje i upravljanje podacima, zahvaljujući efikasnom sistemu za dodjelu memorije i manipulaciju *hash* tablicama.

7. **Jednostavna integracija s drugim strukturama podataka**  
   Rječnici se lako mogu kombinovati s listama, skupovima i drugim strukturama podataka, omogućavajući fleksibilne i kompleksne modele podataka. Na primjer, moguće je imati listu rječnika ili rječnik koji sadrži liste.

8. **Jednostavno proširivanje funkcionalnosti**  
   Rječnici podržavaju brojne metode poput `keys()`, `values()`, `items()`, koje omogućavaju jednostavno iteriranje kroz podatke i proširivanje njihovih funkcionalnosti.

9. **Praktična primjena u realnim scenarijima**  
   Rječnici se koriste u širokom spektru aplikacija, uključujući:
   - Čuvanje konfiguracija (npr. postavke korisnika u aplikaciji).
   - Analizu podataka (npr. brojanje pojavljivanja riječi u tekstu).
   - Rad sa JSON podacima u web aplikacijama.

:::info
### O JSON-u

JSON (*JavaScript Object Notation*) je format za razmjenu podataka koji je postao široko prihvaćen u razvoju softvera. Razvijen kao dio JavaScript programskog jezika. Danas se koristi u skoro svim programskim jezicima, uključujući Python. Njegova jednostavna sintaksa i razumljiva struktura čine ga idealnim za slanje i primanje podataka između različitih sistema.

JSON je stekao popularnost zbog svoje jednostavnosti i čitljivosti. Ključni razlozi su:

1. **Jednostavna sintaksa**: JSON format koristi lako razumljive strukture kao što su objekti i liste, što ga čini intuitivnim za rad.  
   - Objekti u JSON-u se predstavljaju kao **ključ-vrijednost** parovi, baš kao rječnici u Pythonu.
   - Liste se koriste za grupisanje povezanih podataka.

2. **Univerzalna kompatibilnost**: JSON se koristi u različitim programskim jezicima i alatima, što ga čini odličnim izborom za razmjenu podataka između sistema.

3. **Široka primjena**: JSON je standard u razvoju web aplikacija, posebno za razmjenu podataka između klijentske strane (frontend) i serverske strane (backend).

4. **Laka manipulacija**: U Pythonu, biblioteka `json` omogućava jednostavno konvertovanje podataka između JSON formata i Python struktura podataka, poput rječnika.

#### JSON i rječnici

JSON format ima direktnu povezanost sa rječnicima u Pythonu, jer koristi isti model **ključ-vrijednost** za organizaciju podataka. Ovo čini konvertovanje JSON podataka u rječnike (i obrnuto) izuzetno jednostavnim.

Ispod je prikazan JSON objekat.
```json=
{
    "naziv": "Bosna i Hercegovina",
    "glavni_grad": "Sarajevo",
    "kontinent": "Evropa",
    "stanovnistvo": 3280819
}
```

Nakon učitavanja u Python, automatski se pretvara u rječnik.
```python=
{
    "naziv": "Bosna i Hercegovina",
    "glavni_grad": "Sarajevo",
    "kontinent": "Evropa",
    "stanovnistvo": 3280819
}
```

#### Kako raditi sa JSON-om u Pythonu?

Python nudi biblioteku `json` koja omogućava jednostavno čitanje i pisanje JSON podataka.

**Konvertovanje JSON-a u rječnik (parsiranje)**:
  ```python=
  import json

  json_podaci = '{"naziv": "Bosna i Hercegovina", "glavni_grad": "Sarajevo"}'
  rjecnik = json.loads(json_podaci)
  print(rjecnik["glavni_grad"])
  ```
  <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Sarajevo</pre>

**Konvertovanje rječnika u JSON (serijalizacija)**:
  ```python=
  podaci = {
      "naziv": "Bosna i Hercegovina",
      "glavni_grad": "Sarajevo"
  }
  json_podaci = json.dumps(podaci)
  print(json_podaci)
  ```
  <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{"naziv": "Bosna i Hercegovina", "glavni_grad": "Sarajevo"}  </pre>

#### Gdje se JSON koristi?

- **Web aplikacije**: Za razmjenu podataka između klijenta i servera.
- **API-jevi**: JSON je standard za REST API-jeve.
- **Pohrana podataka**: JSON se koristi za čuvanje konfiguracija i manjih setova podataka.
- **Razmjena podataka**: JSON omogućava jednostavno prenošenje podataka između različitih platformi i jezika.

JSON predstavlja most između različitih tehnologija, a zahvaljujući sličnosti s rječnicima u Pythonu, omogućava jednostavno učenje i primjenu u raznim projektima.
:::


# Skupovi

Skupovi su posebna struktura podataka u programiranju koja omogućava rad s kolekcijama elemenata gdje se eliminacija duplikata i brzo pretraživanje ističu kao glavne karakteristike. Inspirisani matematičkim konceptom skupova, oni omogućavaju rad s podacima kroz operacije poput unije, presjeka, razlike i simetrične razlike.

Za razliku od listi ili rječnika (od verzija Pythona 3.7), skupovi ne čuvaju elemente u određenom redoslijedu. Umjesto toga, svaki element u skupu mora biti jedinstven, čime se osigurava integritet podataka i olakšava pretraživanje.

Uvođenjem skupova u programiranje rješava se niz problema povezanih s rukovanjem duplikatima, provjerom pripadnosti elemenata i izvršavanjem kompleksnih skupovnih operacija. Zbog toga su skupovi nezaobilazan alat u situacijama gdje je bitna brzina i jednostavnost upravljanja velikim količinama podataka.

## Ključne osobine skupova

Skupovi u Pythonu posjeduju nekoliko ključnih osobina koje ih čine jedinstvenim i korisnim za određene primjene u programiranju.

Prva važna osobina skupova je da su **elementi unutar skupa uvijek jedinstveni**. Kada se skup kreira, svi duplikati se automatski uklanjaju. Ovo znači da skupovi mogu biti izuzetno korisni za filtriranje duplikata iz listi ili drugih kolekcija podataka, čime se pojednostavljuje rad s podacima gdje je jedinstvenost ključna.

Druga osobina skupova je njihova **neuređenost**, što znači da elementi unutar skupa nemaju određeni redoslijed. Ovo svojstvo ih razlikuje od struktura poput listi i rječnika, gdje redoslijed igra značajnu ulogu. Zbog neuređenosti, nije moguće pristupiti elementima skupa putem indeksa kao kod listi.

Treća i jedna od najvažnijih osobina skupova je njihova **efikasnost**. Zahvaljujući internim mehanizmima za pohranu podataka, koji koriste *hash* tablice, operacije poput provjere da li određeni element pripada skupu (`in`) izvršavaju se izuzetno brzo. Ova efikasnost čini skupove idealnim za rad sa velikim kolekcijama podataka gdje je važno brzo pretraživanje ili provjera prisustva elemenata.

## Definicija i kreiranje skupova

Skupovi u programiranju se definišu kao kolekcije **neuređenih** i **jedinstvenih** elemenata. U Pythonu, skupovi se stvaraju pomoću ključne riječi `set` ili korištenjem vitičastih zagrada `{}` za definisanje elemenata. Elementi unutar skupa mogu biti bilo kojeg **nepromjenjivog tipa**, poput brojeva, stringova ili tuple-ova, dok **promjenjivi tipovi**, poput lista ili drugih skupova, nisu dozvoljeni.

### Kreiranje skupa

Skupovi u Pythonu mogu se kreirati na različite načine, u zavisnosti od potreba i vrste podataka. U ovom dijelu će biti objašnjeno kako se definišu skupovi, zajedno s primjerima koji prikazuju njihovu praktičnu primjenu.

#### Kreiranje skupa s elementima

Skupovi se mogu kreirati direktno navođenjem elemenata unutar `{}` ili konverzijom postojećih struktura podataka (npr. lista, stringova) u skup koristeći `set()`:

```python=
# Skup s elementima
skup_gradova = {"Sarajevo", "Mostar", "Tuzla", "Banja Luka"}
print(skup_gradova)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{'Sarajevo', 'Banja Luka', 'Mostar', 'Tuzla'}
</pre>

Skupovi se mogu kreirati i konverzijom liste u skup.
```python=
# Lista s duplikatima
gradovi = ["Sarajevo", "Mostar", "Tuzla", "Mostar", "Banja Luka"]

# Konverzija u skup
skup_gradova = set(gradovi)
print(skup_gradova)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{'Sarajevo', 'Banja Luka', 'Mostar', 'Tuzla'}
</pre>

Ova metoda je korisna za uklanjanje duplikata iz drugih struktura podataka, kao što je u primjeru uklonjeno drugo pojavljivanje elementa "Mostar".

:::info
### Kreiranje praznog skupa

Za razliku od listi ili rječnika, kreiranje praznog skupa u Pythonu zahtijeva korištenje funkcije `set()`. Korištenje `{}` stvara prazan rječnik, a ne skup. U primjeru ispod, prikazan je način kreiranja praznog skupa.

```python=
# Kreiranje praznog skupa
prazan_skup = set()
print(prazan_skup)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
set()
</pre>

Ako se koristi `{}`, Python interpretira ovu sintaksu kao prazan rječnik.
```python=
prazan_rjecnik = {}
print(type(prazan_rjecnik))
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
<class 'dict'>
</pre>
:::

## Osnovne operacije sa skupovima

Skupovi u Pythonu pružaju širok spektar osnovnih operacija koje omogućavaju efikasno upravljanje elementima. Dodavanje, uklanjanje i provjera elemenata su ključne funkcionalnosti koje se koriste u gotovo svim primjenama. U nastavku su detaljno objašnjene ove operacije uz primjere.

### Dodavanje elemenata (`add`)

Dodavanje elemenata u skup obavlja se metodom `add()`. Ova metoda omogućava dodavanje jednog elementa u skup. Ako element već postoji, neće se dodati ponovo, jer skupovi ne dozvoljavaju duplikate. 

```python=
skup_gradova = {"Sarajevo", "Mostar", "Banja Luka"}
skup_gradova.add("Tuzla")
skup_gradova.add("Sarajevo")
print(skup_gradova)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{'Sarajevo', 'Tuzla', 'Banja Luka', 'Mostar'}
</pre>

Dodavanje elemenata u skup je brza operacija zbog internog načina pohrane podataka. Važno je obratiti pažnju da poredak u ispisu nije zagarantovan.

### Uklanjanje elemenata (`remove`, `discard`, `pop`)

Uklanjanje elemenata iz skupa može se izvršiti na nekoliko načina:

- **`remove`**: Uklanja određeni element iz skupa. Ako element ne postoji, Python baca grešku.
- **`discard`**: Također uklanja određeni element, ali ne baca grešku ako element ne postoji.
- **`pop`**: Uklanja i vraća nasumičan element iz skupa. Ako je skup prazan, baca grešku.

Ispod su prikazane upotrebe metoda `remove` i `discard`.

```python=
# Uklanjanje elementa pomoću remove
skup_gradova.remove("Mostar")
print(skup_gradova)

# Uklanjanje elementa pomoću discard
skup_gradova.discard("Mostar")  # Ne baca grešku
print(skup_gradova)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{'Sarajevo', 'Tuzla', 'Banja Luka'}
</pre>


Metoda `pop()` koristi se za uklanjanje nasumičnog elementa iz skupa. Ova metoda također vraća uklonjeni element, što omogućava njegovu daljnju upotrebu.


```python=
skup_gradova = {"Sarajevo", "Mostar", "Banja Luka", "Tuzla"}
element = skup_gradova.pop()
print(f"Uklonjen element: {element}")
print(skup_gradova)
```

Jedan od mogućih ispisa, naveden je ispod.

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Uklonjen element: Banja Luka
{'Sarajevo', 'Mostar', 'Tuzla'}
</pre>

Dakle, element koji se uklanja je nasumično odabran. Ako se metoda `pop()` koristi više puta, svaki put će se ukloniti i vratiti drugačiji element dok skup ne postane prazan.

:::info
**Kada koristiti metodu `pop`?**

Metoda `pop()` ima smisla u specifičnim scenarijima, od kojih su neki navedeni ispod:
1. **Iterativna obrada elemenata skupa dok se ne isprazni**  
   Ova situacija se javlja kada je neophodno obraditi sve elemente, ali redoslijed obrade nije bitan.

   ```python=
   while skup_gradova:
       element = skup_gradova.pop()
       print(f"Obrađuje se grad: {element}")
   ```

   Mogući ispis naveden je u nastavku.
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
   Obrađuje se grad: Tuzla  
   Obrađuje se grad: Mostar  
   Obrađuje se grad: Sarajevo  
   Obrađuje se grad: Banja Luka
   </pre>

2. **Nasumično biranje elemenata za neku operaciju**  
   Kada se nasumično odabrani element koristi za neku logiku, npr. u igricama ili simulacijama.

   ```python=
   igra_skup = {"igrač1", "igrač2", "igrač3", "igrač4"}
   odabrani_igrač = igra_skup.pop()
   print(f"Nasumično odabrani igrač: {odabrani_igrač}")
   ```

   Mogući ispis u ovom slučaju je:
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
   Nasumično odabrani igrač: igrač3
   </pre>

:::

### Provjera pripadnosti (`in`)

Provjera da li se određeni element nalazi u skupu obavlja se korištenjem operatora `in`. Ova operacija je izuzetno brza zbog načina na koji skupovi pohranjuju podatke, te je izuzetno korisna za brzo filtriranje ili provjeru podataka.

```python=
print("Sarajevo" in skup_gradova)  # True
print("Konjic" in skup_gradova)    # False
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
True  
False
</pre>


### Broj elemenata (`len`)

Metoda `len()` vraća broj elemenata u skupu. Korisna je kada je potrebno pratiti veličinu skupa, posebno prilikom rada s dinamičkim podacima.

```python=
print(len(skup_gradova))
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
4
</pre>


## Skupovne operacije

Skupovi u Pythonu pružaju niz matematičkih i logičkih operacija koje omogućavaju manipulaciju podacima na intuitivan i efikasan način. Ove operacije uključuju uniju, presjek, razliku i simetričnu razliku, a koriste se u raznim scenarijima, poput poređenja podataka, filtriranja i analize skupova.

### Unija (`union`)

Unija dva skupa predstavlja skup koji sadrži sve jedinstvene elemente iz oba skupa. Elementi se automatski filtriraju kako bi se uklonili duplikati. Ova operacija je korisna kada se želi kombinovati više izvora podataka.

```python=
A = {1, 2, 3}
B = {3, 4, 5}
unija = A.union(B)
print(unija)
```

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{1, 2, 3, 4, 5}
</pre>


### Presjek (`intersection`)

Presjek dva skupa sadrži samo elemente koji su zajednički za oba skupa. Ova operacija se koristi za identifikaciju podudaranja između dva skupa podataka.

```python=
presjek = A.intersection(B)
print(presjek)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{3}
</pre>


### Razlika (`difference`)

Razlika između dva skupa predstavlja elemente koji su prisutni u prvom skupu, ali ne i u drugom. Ovo je korisno za identifikaciju elemenata koji nisu zajednički u skupovima.

```python=
razlika = A.difference(B)
print(razlika)
```

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{1, 2}
</pre>


### Simetrična razlika (`symmetric_difference`)

Simetrična razlika uključuje sve elemente koji su prisutni u jednom, ali ne i u oba skupa. Korisna je za identifikaciju razlika između dva skupa.

```python=
simetricna_razlika = A.symmetric_difference(B)
print(simetricna_razlika)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{1, 2, 4, 5}
</pre>

:::info
### Analiza tekstualnih podataka pomoću skupova

Skupovi se često koriste za analizu i poređenje tekstualnih podataka. Neka su napisana dva teksta o Sarajevu. Ukoliko je zadatak analizirati riječi u tim tekstovima, te otkriti zajedničke, različite i specifične riječi za svaki fajl, rješenje se može postići jednostavnim korištenjem skupova i njihovih operacija.


Neka tekstovi izgledaju ovako:

- **Tekst 1 (A):**  
  "Sarajevo je glavni grad Bosne i Hercegovine. Poznato je po svojoj bogatoj historiji i raznolikosti kultura."

- **Tekst 2 (B):**  
  "Sarajevo je grad koji spaja istok i zapad. Njegova historija i kultura fasciniraju posjetioce iz cijelog svijeta."

#### Učitavanje tekstova u skupove

Tekstovi se učitavaju u skupove, gdje svaka riječ predstavlja element skupa.

```python=
tekst_1 = "Sarajevo je glavni grad Bosne i Hercegovine. Poznato je po svojoj bogatoj historiji i raznolikosti kultura."
tekst_2 = "Sarajevo je grad koji spaja istok i zapad. Njegova historija i kultura fasciniraju posjetioce iz cijelog svijeta."

# Konverzija u skupove riječi
A = set(tekst_1.lower().replace(".", "").split())
B = set(tekst_2.lower().replace(".", "").split())

print(f"Riječi iz teksta 1: {A}")
print(f"Riječi iz teksta 2: {B}")
```

#### Analiza pomoću skupovnih operacija

1. Sve riječi koje se pojavljuju u bilo kojem tekstu (unija):
   ```python=
   unija = A.union(B)
   print(unija)
   ```
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">{'sarajevo', 'je', 'glavni', 'grad', 'bosne', 'i', 'hercegovine', 'poznato', 'po', 'svojoj', 'bogatoj', 'historiji', 'raznolikosti', 'kultura', 'koji', 'spaja', 'istok', 'zapad', 'njegova', 'fasciniraju', 'posjetioce', 'iz', 'cijelog', 'svijeta'}
   </pre>

2. Zajedničke riječi u oba teksta (presjek):
   ```python=
   presjek = A.intersection(B)
   print(presjek)
   ```
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
   {'sarajevo', 'je', 'grad', 'historiji', 'kultura', 'i'}
   </pre>

3. Riječi koje su samo u tekstu 1, ali ne u tekstu 2 (razlika):
   ```python=
   razlika_a = A.difference(B)
   print(razlika_a)
   ```
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
   {'glavni', 'poznato', 'po', 'svojoj', 'bogatoj', 'bosne', 'hercegovine', 'raznolikosti'}
   </pre>

4. Riječi koje su samo u tekstu 2, ali ne u tekstu 1 (razlika):
   ```python=
   razlika_b = B.difference(A)
   print(razlika_b)
   ```
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
   {'koji', 'spaja', 'istok', 'zapad', 'njegova', 'fasciniraju', 'posjetioce', 'iz', 'cijelog', 'svijeta'}
   </pre>

5. Riječi koje su različite između dva teksta (simetrična razlika):
   ```python=
   simetricna_razlika = A.symmetric_difference(B)
   print(simetricna_razlika)
   ```
   <pre style="background-color: #1e1e1e; color: white; padding: 20px;">
   {'glavni', 'poznato', 'po', 'svojoj', 'bogatoj', 'bosne', 'hercegovine', 'raznolikosti', 'koji', 'spaja', 'istok', 'zapad', 'njegova', 'fasciniraju', 'posjetioce', 'iz', 'cijelog', 'svijeta'}
   </pre>

Korištenjem skupovnih operacija, moguće je na jednostavan način analizirati sličnosti i razlike između dva teksta. Ove tehnike su korisne u obradi prirodnog jezika, analizi podataka i mnogim drugim oblastima programiranja, a velika im je prednost brzina i jednostavnost koda.
:::


## Relacije između skupova

Relacije između skupova koriste se za poređenje njihovih elemenata kako bi se odredilo da li je jedan skup podskup ili nadskup drugog, ili da li su skupovi disjunktni. Ove relacije omogućavaju preciznu analizu odnosa između podataka.

### Provjera podskupa (`issubset`)

Provjerava se da li su svi elementi jednog skupa sadržani u drugom. Ukoliko je svaki element skupa `A` prisutan u skupu `B`, kaže se da je `A` podskup `B`.

```python=
print(A.issubset(B))  # False
print({3}.issubset(B))  # True
```

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
False  
True
</pre>

U primjeru iznad, utvrđuje se da skup `A` nije podskup `B`, dok je skup koji sadrži samo broj `3` podskup `B`.

### Provjera nadskupa (`issuperset`)

Provjerava se da li jedan skup sadrži sve elemente drugog skupa. Ukoliko skup `B` obuhvata sve elemente skupa `A`, smatra se da je `B` nadskup `A`.

```python=
print(B.issuperset(A))  # False
print(B.issuperset({3}))  # True
```

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
False  
True
</pre>

U primjeru je pokazano da skup `B` nije nadskup `A`, ali jeste nadskup skupa koji sadrži broj 3.

### Provjera disjunktnosti (`isdisjoint`)

Dva skupa se smatraju disjunktnima ukoliko nemaju zajedničkih elemenata. Pomoću metode `isdisjoint` utvrđuje se da li je presjek između dva skupa prazan.

```python=
print(A.isdisjoint({6, 7, 8}))  # True
print(A.isdisjoint(B))  # False
```

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
True  
False
</pre>

U navedenom primjeru, skup `A` nema zajedničkih elemenata sa skupom koji sadrži brojeve 6, 7 i 8, pa se smatra disjunktnim. Međutim, skup `A` i skup `B` nisu disjunktni, jer dijele zajednički element.


:::info
### Skupovi i liste

Jedna od glavnih prednosti skupova je njihova sposobnost automatskog uklanjanja duplikata, što ih čini korisnim za rad sa podacima gdje jedinstvenost elemenata igra ključnu ulogu. Na primjer, lista s duplikatima se jednostavno može konvertovati u skup kako bi se dobio niz jedinstvenih vrijednosti, kao u primjeru ispod.

```python=
lista = [1, 2, 2, 3, 4, 4, 5]
skup = set(lista)
print(skup)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
{1, 2, 3, 4, 5}
</pre>

Kada je neophodno pretvoriti skup u listu, može se koristiti funkcija `list()`.

```python=
jedinstvena_lista = list(skup)
print(jedinstvena_lista)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
[1, 2, 3, 4, 5]
</pre>
:::


## Iteracija kroz skupove

Iteracija kroz skupove omogućava prolazak kroz sve elemente skupa koristeći `for` petlju. Za razliku od listi ili drugih uređenih struktura podataka, skupovi ne garantuju redoslijed elemenata prilikom iteracije, jer su **neuređeni**.

### Osnovna iteracija

Jednostavna iteracija kroz skup može se postići korištenjem `for` petlje. Svaki element skupa se obradi jednom, ali redoslijed nije definisan.

```python=  
skup_gradova = {"Sarajevo", "Mostar", "Banja Luka", "Tuzla"}

for grad in skup_gradova:
    print(grad)
```

Mogući ispis naveden je ispod.

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Sarajevo  
Tuzla  
Mostar  
Banja Luka
</pre>


### Iteracija sa brojanjem

U nekim slučajevima, potrebno je iterirati kroz skup i istovremeno pratiti redni broj svakog elementa. Ovo se može postići koristeći funkciju `enumerate()`.

```python=  
for indeks, grad in enumerate(skup_gradova, start=1):
    print(f"{indeks}. {grad}")
```

Mogući ispis naveden je ispod.

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
1. Sarajevo  
2. Tuzla  
3. Mostar  
4. Banja Luka
</pre>

### Iteracija u kombinaciji s uslovima

Iteracija kroz skupove često se koristi u kombinaciji s logičkim uslovima za filtriranje elemenata koji zadovoljavaju određeni kriterij. Na primjer, neka je zadatak izdvojiti gradove čija imena imaju više od šest slova.

```python=  
dugi_gradovi = {grad for grad in skup_gradova if len(grad) > 6}
print(f"Gradovi s više od šest slova: {dugi_gradovi}")
```

Ispis je naveden ispod. 

<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
Gradovi s više od šest slova: {'Sarajevo', 'Banja Luka'}
</pre>

**Šta se dešava u prvoj liniji koda?**

Prva linija koristi **set comprehension**, elegantnu i efikasnu tehniku za generisanje skupova na osnovu postojećih podataka uz dodatne uslove. Proces funkcioniše korak po korak na sljedeći način:
1. **Inicijalizacija iteracije**: Skup `skup_gradova` se iterira koristeći `for grad in skup_gradova`. U svakoj iteraciji, trenutni element (npr. "Sarajevo") se dodjeljuje varijabli `grad`.
2. **Primjena uslova**: Za svaki element iz skupa provjerava se logički uslov `if len(grad) > 6`. Ovdje se izračunava dužina imena grada koristeći funkciju `len()`. Samo gradovi čija imena imaju više od šest slova prolaze ovu provjeru.
3. **Dodavanje u skup**: Ako grad zadovoljava uslov, dodaje se u novi skup `dugi_gradovi`. Ovo osigurava da rezultirajući skup sadrži samo gradove koji ispunjavaju zadati kriterij.
4. **Rezultat**: Na kraju, skup `dugi_gradovi` sadrži jedinstvene elemente koji ispunjavaju uslov. Redoslijed elemenata nije zagarantovan, jer su skupovi neuređeni.

Primjena ovakve konstrukcije omogućava efikasno i sažeto filtriranje podataka, čineći kod čitljivim i jednostavnim za održavanje. U ovom primjeru, koristeći samo jednu liniju koda, izdvojeni su gradovi koji imaju više od šest slova, bez potrebe za dodatnim strukturama ili metodama.


:::info
### Rad sa nepromjenjivim skupovima (frozenset)

Osim običnih skupova, Python podržava i nepromjenjive skupove koji se kreiraju koristeći funkciju `frozenset()`. Jednom kreiran, `frozenset` ne dozvoljava dodavanje, uklanjanje ili mijenjanje elemenata. Ova struktura podataka je korisna kada je potrebno zaštititi podatke od modifikacija.

```python=
nepromjenjivi_skup = frozenset(["Sarajevo", "Mostar", "Banja Luka"])
print(nepromjenjivi_skup)
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
frozenset({'Sarajevo', 'Banja Luka', 'Mostar'})
</pre>

Pokušaj modifikacije rezultira greškom:
```python=
nepromjenjivi_skup.add("Tuzla")
```
<pre style="background-color: #1e1e1e; color: white; padding: 20px;">
AttributeError: 'frozenset' object has no attribute 'add'
</pre>
:::

# Sažetak

Rječnici i skupovi predstavljaju dvije ključne strukture podataka u Python programskom jeziku, omogućavajući efikasno čuvanje, organizaciju i manipulaciju informacijama. Iako su liste osnovna kolekcija za pohranu nizova podataka, rječnici i skupovi pružaju naprednija rješenja za rad s kompleksnijim podacima i situacijama gdje su brzina i jedinstvenost elemenata ključne.  

Rječnici su strukturirani u formatu **ključ-vrijednost**, što omogućava direktan pristup podacima putem njihovih ključeva. Ovakav pristup značajno ubrzava pretragu i povećava čitljivost koda, jer omogućava dohvaćanje podataka na intuitivan način bez potrebe za korištenjem pozicija kao kod listi. Svaki ključ u rječniku mora biti jedinstven i nepromjenjiv, dok vrijednosti mogu biti bilo kojeg tipa – od brojeva i stringova do lista i drugih rječnika. Ova fleksibilnost čini rječnike idealnim za opisivanje objekata, konfiguracija i podataka koji dolaze u formatu sličnom JSON-u.  

Skupovi s druge strane predstavljaju kolekcije **jedinstvenih i neuređenih elemenata**. Njihova glavna prednost leži u automatskom uklanjanju duplikata i brzoj provjeri pripadnosti elemenata, što se postiže zahvaljujući internim hash tablicama. Skupovi omogućavaju jednostavne operacije poput **unije, presjeka, razlike i simetrične razlike** između različitih kolekcija podataka, čineći ih korisnim za filtriranje i analizu. Njihova efikasnost u pretraživanju (`in` operator) čini ih posebno pogodnim za rad s velikim količinama podataka gdje je brzina ključna.  

Pored osnovnih operacija poput dodavanja (`add`) i uklanjanja (`remove`, `discard`), skupovi nude napredne mogućnosti kroz metode kao što su `union()`, `intersection()` i `difference()`. Iteracija kroz skupove je jednostavna, ali se elementi ne čuvaju u određenom redoslijedu, što je ključna razlika u odnosu na liste i rječnike.  

I rječnici i skupovi pružaju brojne prednosti u radu s podacima, omogućavajući organizaciju koja je istovremeno jednostavna i efikasna. Njihova upotreba doprinosi optimizaciji koda i povećava njegovu čitljivost, čineći ih nezaobilaznim alatima u svakodnevnom programiranju.