Tuples and Sets - Special Collection Types

Tuples are like lists but immutable (cannot be changed after creation). Use for fixed data like coordinates. Sets store unique items only (no duplicates) and are unordered. Great for checking membership and mathematical operations.

# Tuples and Sets examples
# ========== TUPLES ==========
print("PART 1: TUPLES")
print("=" * 30)

# Example 1: Creating tuples
print("\nExample 1: Creating and accessing tuples")
coordinates = (10, 20)
colors = ("red", "green", "blue")
person = ("Alice", 25, "Engineer")

print(f"Coordinates: {coordinates}")
print(f"First color: {colors[0]}")
print(f"Person: Name={person[0]}, Age={person[1]}, Job={person[2]}")

# Tuples are immutable - this would cause error:
# coordinates[0] = 15  # TypeError!

# Example 2: Tuple unpacking
print("\nExample 2: Tuple unpacking")
x, y = coordinates
print(f"X coordinate: {x}")
print(f"Y coordinate: {y}")

name, age, job = person
print(f"Unpacked: {name} is {age} years old and works as {job}")

# Example 3: Functions returning tuples
print("\nExample 3: Functions with tuples")

def get_min_max(numbers):
    """Returns (minimum, maximum) as tuple"""
    return min(numbers), max(numbers)

scores = [85, 92, 78, 90, 88]
min_score, max_score = get_min_max(scores)
print(f"Scores: {scores}")
print(f"Minimum: {min_score}, Maximum: {max_score}")

# Example 4: Using tuples as dictionary keys
print("\nExample 4: Tuples as dictionary keys")
# Lists can't be dictionary keys, but tuples can!
locations = {
    (40.7128, -74.0060): "New York",
    (51.5074, -0.1278): "London",
    (35.6762, 139.6503): "Tokyo"
}

my_location = (40.7128, -74.0060)
print(f"Coordinates {my_location} = {locations[my_location]}")

# ========== SETS ==========
print("\n\nPART 2: SETS")
print("=" * 30)

# Example 5: Creating sets
print("\nExample 5: Creating and using sets")
fruits = {"apple", "banana", "orange", "apple"}  # Duplicate removed
numbers = set([1, 2, 3, 2, 1])  # From list

print(f"Fruits set: {fruits}")  # Note: No duplicates
print(f"Numbers set: {numbers}")

# Example 6: Set operations
print("\nExample 6: Set operations")
set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}

print(f"Set A: {set_a}")
print(f"Set B: {set_b}")
print(f"Union (A | B): {set_a | set_b}")  # All elements
print(f"Intersection (A & B): {set_a & set_b}")  # Common elements
print(f"Difference (A - B): {set_a - set_b}")  # In A but not B
print(f"Symmetric Difference (A ^ B): {set_a ^ set_b}")  # In one but not both

# Example 7: Membership testing
print("\nExample 7: Fast membership testing")
vowels = {'a', 'e', 'i', 'o', 'u'}
word = "hello"

found_vowels = []
for letter in word:
    if letter in vowels:  # Very fast with sets!
        found_vowels.append(letter)

print(f"Word: {word}")
print(f"Vowels found: {found_vowels}")
print(f"Unique vowels: {set(found_vowels)}")

# Example 8: Removing duplicates from list
print("\nExample 8: Removing duplicates")
grades = [85, 90, 85, 88, 90, 92, 85]
unique_grades = set(grades)
sorted_grades = sorted(unique_grades)

print(f"All grades: {grades}")
print(f"Unique grades: {unique_grades}")
print(f"Sorted unique grades: {sorted_grades}")

# Example 9: Set methods
print("\nExample 9: Set methods")
todo_set = {"read", "exercise", "code"}
print(f"Original: {todo_set}")

todo_set.add("meditate")
print(f"After add: {todo_set}")

todo_set.remove("exercise")  # Error if not found
print(f"After remove: {todo_set}")

todo_set.discard("sleep")  # No error if not found
print(f"After discard: {todo_set}")

popped = todo_set.pop()  # Removes random element
print(f"Popped: {popped}")
print(f"Final set: {todo_set}")

# Example 10: Comparing sets
print("\nExample 10: Set comparisons")
required = {"math", "science", "english"}
student1 = {"math", "science", "history", "art"}
student2 = {"math", "science", "english", "physics"}

print(f"Required courses: {required}")
print(f"Student 1 courses: {student1}")
print(f"Student 2 courses: {student2}")
print(f"\nStudent 1 missing: {required - student1}")
print(f"Student 2 missing: {required - student2}")
print(f"Student 1 has all required? {required.issubset(student1)}")
print(f"Student 2 has all required? {required.issubset(student2)}")