# Ordered. Fixed. Useful.
# tuples in practice — indexing, unpacking, looping, dict keys

soldier = ("Raven", 85, True, "Sergeant")

# ─────────────────────────────────────────────
# Indexing and slicing
# ─────────────────────────────────────────────

print(soldier[0])       # Raven
print(soldier[-1])      # Sergeant
print(soldier[1:3])     # (85, True) — slice returns a tuple

# ─────────────────────────────────────────────
# Looping
# ─────────────────────────────────────────────

colors = ("red", "green", "blue")
for color in colors:
    print(color)

# red / green / blue

for i, color in enumerate(colors):
    print(f"{i}: {color}")

# 0: red / 1: green / 2: blue

# ─────────────────────────────────────────────
# Unpacking — one line, multiple variables
# ─────────────────────────────────────────────

location = (44.4268, 26.1025)
lat, lon = location
print(lat)      # 44.4268
print(lon)      # 26.1025

soldier = ("Raven", 85, "Sergeant")
name, score, rank = soldier
print(f"{name} — {rank} — score: {score}")
# Raven — Sergeant — score: 85

# number of variables must match number of elements
# name, score = soldier     # ValueError: too many values to unpack

# ─────────────────────────────────────────────
# Multiple return values — tuple under the hood
# ─────────────────────────────────────────────

def min_max(numbers):
    return min(numbers), max(numbers)   # returns a tuple

low, high = min_max([85, 74, 91, 63, 98])
print(low)      # 63
print(high)     # 98

result = min_max([85, 74, 91])
print(result)           # (74, 91)
print(type(result))     # <class 'tuple'>

# ─────────────────────────────────────────────
# Membership, counting, length
# ─────────────────────────────────────────────

colors = ("red", "green", "blue", "red")

print("red" in colors)          # True
print("yellow" in colors)       # False
print(colors.count("red"))      # 2
print(colors.index("green"))    # 1
print(len(colors))              # 4

# ─────────────────────────────────────────────
# Tuples as dict keys
# ─────────────────────────────────────────────

locations = {
    (44.4268, 26.1025): "Bucharest",
    (48.8566, 2.3522):  "Paris",
    (51.5074, -0.1278): "London"
}

print(locations[(44.4268, 26.1025)])    # Bucharest
print(locations[(48.8566, 2.3522)])     # Paris

# lists cannot be dict keys — tuples can
# {[1, 2]: "value"}    # TypeError: unhashable type: 'list'

# ─────────────────────────────────────────────
# Converting tuple ↔ list
# ─────────────────────────────────────────────

soldier = ("Raven", 85, True)
temp = list(soldier)        # tuple → list
temp[1] = 91                # modify
soldier = tuple(temp)       # list → tuple
print(soldier)              # ('Raven', 91, True)

# ─────────────────────────────────────────────
# Quick reference
# ─────────────────────────────────────────────

# t[i]              — element at index i
# t[a:b]            — slice (returns tuple)
# for x in t        — iterate
# a, b = t          — unpack (variables must match length)
# x in t            — membership check
# t.count(x)        — count occurrences
# t.index(x)        — index of first match
# len(t)            — number of elements
# list(t)           — convert to list
# tuple(lst)        — convert to tuple
#
# tuples can be dict keys — lists cannot
# slicing returns a tuple, not a list
