📋 PROMEMORIA: LISTE ANNIDATE IN PYTHON


# ═══════════════════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════════════════

# ─────────────────────────────────────────────────────────────────────────────
# 📌 COSA SONO LE LISTE ANNIDATE
# ─────────────────────────────────────────────────────────────────────────────
# Le liste annidate sono liste che contengono altre liste come elementi.
# Permettono di organizzare dati complessi e correlati in strutture ordinate.
#
# Utilità: ideali quando ogni elemento ha attributi multipli
# Esempio: prodotto con [nome, prezzo, quantità, tipo]


# ─────────────────────────────────────────────────────────────────────────────
# 🔍 INDICIZZAZIONE MULTIPLA
# ─────────────────────────────────────────────────────────────────────────────
# Per accedere agli elementi di liste annidate si usa l'indicizzazione multipla:
#
# Sintassi: lista[indice_esterno][indice_interno]
#           ↑                    ↑
#           seleziona sottolista  seleziona elemento dentro la sottolista

# Esempio pratico:
grocery_list = [
    ["Bread", 4.80, 3, "Gluten Free"],
    ["Milk", 5.99, 2, "2% Milk"],
    ["Apple", 1.27, 12, "Fuji"]
]

# grocery_list[1] → ["Milk", 5.99, 2, "2% Milk"]
# grocery_list[1][0] → "Milk" (nome)
# grocery_list[1][1] → 5.99 (prezzo)
# grocery_list[1][2] → 2 (quantità)
# grocery_list[1][3] → "2% Milk" (tipo)


# ─────────────────────────────────────────────────────────────────────────────
# 🧪 ESEMPIO COMPLETO: LISTA DELLA SPESA
# ─────────────────────────────────────────────────────────────────────────────

# Passo 1: Creare le sottoliste per ogni prodotto
# Formato: [nome, prezzo, quantità, tipo]
bread = ["Bread", 4.80, 3, "Gluten Free"]
milk = ["Milk", 5.99, 2, "2% Milk"]
apple = ["Apple", 1.27, 12, "Fuji"]

# Passo 2: Creare la lista principale contenente tutte le sottoliste
grocery_list = [bread, apple, milk]
print("Grocery List:", grocery_list)

# Passo 3: Accedere ai dettagli di un articolo specifico
# Esempio: accedere ai dettagli del "Milk" (posizione 2)
print("Item:", grocery_list[2][0])      # → "Milk"
print("Price:", grocery_list[2][1])     # → 5.99
print("Quantity:", grocery_list[2][2])  # → 2
print("Type:", grocery_list[2][3])      # → "2% Milk"

# Passo 4: Aggiungere un nuovo articolo
onion = ["Onions", 1.30, 10, "Yellow"]
grocery_list.append(onion)
# Ora la lista contiene: [bread, apple, milk, onion]

# Passo 5: Rimuovere un articolo
grocery_list.remove(bread)
# Ora la lista contiene: [apple, milk, onion]

# Passo 6: Ordinare alfabeticamente (ordina per il primo elemento di ogni sottolista)
grocery_list.sort()
print("Updated Grocery List:", grocery_list)
# Output: [["Apple", 1.27, 12, "Fuji"], ["Milk", 5.99, 2, "2% Milk"], ["Onions", 1.30, 10, "Yellow"]]


# ─────────────────────────────────────────────────────────────────────────────
# 💡 OPERAZIONI COMUNI CON LISTE ANNIDATE
# ─────────────────────────────────────────────────────────────────────────────

# 1. Verificare se un elemento è già presente prima di aggiungerlo
vegetables = ["tomatoes", "potatoes", "onions"]

if "carrots" not in vegetables:
    vegetables.append("carrots")
else:
    print("Carrots are already in the list.")

# 2. Rimuovere elementi
vegetables.remove("onions")

# 3. Aggiungere con controllo duplicati
if "cucumbers" not in vegetables:
    vegetables.append("cucumbers")
else:
    print("Cucumbers are already in the list.")

# 4. Ordinare alfabeticamente
vegetables.sort()

# 5. Stampare risultato finale
print(f"Updated Vegetable Inventory: {vegetables}")


# ─────────────────────────────────────────────────────────────────────────────
# 🎯 ESERCIZIO COMPLETO: GESTIONE INVENTARIO VERDURE
# ─────────────────────────────────────────────────────────────────────────────

# Requisiti:
# 1. Creare lista iniziale
# 2. Rimuovere "onions"
# 3. Aggiungere "carrots" (con controllo duplicati)
# 4. Aggiungere "cucumbers" (con controllo duplicati)
# 5. Ordinare alfabeticamente
# 6. Stampare messaggi appropriati
# 7. Stampare lista finale

# Soluzione:
vegetables = ["tomatoes", "potatoes", "onions"]

# Rimuovere onions
vegetables.remove("onions")

# Aggiungere carrots con controllo
if "carrots" not in vegetables:
    vegetables.append("carrots")
else:
    print("Carrots are already in the list.")

# Aggiungere cucumbers con controllo
if "cucumbers" not in vegetables:
    vegetables.append("cucumbers")
else:
    print("Cucumbers are already in the list.")

# Ordinare
vegetables.sort()

# Stampare risultato
print(f"Updated Vegetable Inventory: {vegetables}")
# Output atteso: Updated Vegetable Inventory: ['carrots', 'cucumbers', 'potatoes', 'tomatoes']


# ─────────────────────────────────────────────────────────────────────────────
# 💡 NOTE IMPORTANTI
# ─────────────────────────────────────────────────────────────────────────────

# • L'operatore 'in' verifica la presenza di un elemento nella lista
# • .sort() ordina le liste annidate in base al PRIMO elemento di ogni sottolista
# • Per liste annidate numeriche, l'ordinamento sarà per il primo valore numerico
# • L'indicizzazione multipla può avere più livelli: lista[0][1][2] ecc.
# • Usare 'not in' per verificare l'ASSENZA di un elemento


# ─────────────────────────────────────────────────────────────────────────────
# ✅ CONFRONTO: LISTE SEMPLICI VS LISTE ANNIDATE
# ─────────────────────────────────────────────────────────────────────────────

# Liste semplici: un valore per elemento
fruits = ["apple", "banana", "cherry"]

# Liste annidate: multipli valori per elemento
products = [
    ["apple", 1.27, 12],
    ["banana", 0.59, 6],
    ["cherry", 3.99, 20]
]

# Accesso:
# Liste semplici: fruits[0] → "apple"
# Liste annidate: products[0][0] → "apple", products[0][1] → 1.27

# ═══════════════════════════════════════════════════════════════════════════
# Fine del promemoria
# ═══════════════════════════════════════════════════════════════════════════