# 1. Sorting by Length of Strings
words = ["apple", "banana", "kiwi", "grape"]
sorted_words = sorted(words, key=lambda x: len(x))  # Sort by length of strings
print("Sorted by length:", sorted_words)

# 2. Sorting Strings Alphabetically (Default)
sorted_words = sorted(words, key=lambda x: x)  # Default alphabetical sorting
print("Alphabetically sorted:", sorted_words)

# 3. Sorting by Last Character of Strings
sorted_words = sorted(words, key=lambda x: x[-1])  # Sort by last character of each word
print("Sorted by last character:", sorted_words)

# 4. Sorting Tuples by Second Element
tuples = [(1, 2), (3, 1), (5, 4), (2, 3)]
sorted_tuples = sorted(tuples, key=lambda x: x[1])  # Sort by second element of each tuple
print("Sorted by second element of tuple:", sorted_tuples)

# 5. Sorting by Sum of Elements in Tuples
sorted_tuples = sorted(tuples, key=lambda x: sum(x))  # Sort by sum of elements in each tuple
print("Sorted by sum of elements:", sorted_tuples)

# 6. Sorting a List of Dictionaries by a Specific Key (Age)
students = [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Charlie", "age": 23}]
sorted_students = sorted(students, key=lambda x: x["age"])  # Sort by age
print("Sorted by age:", sorted_students)

# 7. Sorting by Multiple Criteria (Age then Name)
sorted_students = sorted(students, key=lambda x: (x["age"], x["name"]))  # Sort by age, then name
print("Sorted by age and name:", sorted_students)

# 8. Sorting by Absolute Value of Numbers
numbers = [-5, 3, -2, 8, -1]
sorted_numbers = sorted(numbers, key=lambda x: abs(x))  # Sort by absolute value
print("Sorted by absolute value:", sorted_numbers)

# 9. Sorting by Custom Object Attribute (Age)
class Athlete:
    def __init__(self, name, age):
        self.name = name
        self.age = age

athletes = [Athlete("Alice", 25), Athlete("Bob", 22), Athlete("Charlie", 23)]
sorted_athletes = sorted(athletes, key=lambda x: x.age)  # Sort by age of Athlete object
print("Sorted by athlete age:")
for athlete in sorted_athletes:
    print(athlete.name, athlete.age)

# 10. Sorting in Reverse Order
sorted_numbers = sorted(numbers, key=lambda x: x, reverse=True)  # Sort in reverse order
print("Sorted in reverse order:", sorted_numbers)

# 11. Sorting by Length of Words in Sentences
sentence = "The quick brown fox jumps over the lazy dog"
words = sentence.split()
sorted_words = sorted(words, key=lambda x: len(x))  # Sort words by their length
print("Sorted by length of words in sentence:", sorted_words)

# 12. Sorting by First Character of Each Word
sorted_words = sorted(words, key=lambda x: x[0])  # Sort words by their first character
print("Sorted by first character:", sorted_words)

# 13. Sorting by Decimal Value (Floats)
numbers = [3.14, 1.59, 2.65, 7.29]
sorted_numbers = sorted(numbers, key=lambda x: x - int(x))  # Sort by decimal part of floats
print("Sorted by decimal value:", sorted_numbers)

# 14. Sorting by Date (using datetime objects)
from datetime import datetime

dates = [
    datetime(2021, 5, 10),
    datetime(2020, 6, 15),
    datetime(2022, 3, 5),
]

sorted_dates = sorted(dates, key=lambda x: x)  # Sort dates in ascending order
print("Sorted by date:")
for date in sorted_dates:
    print(date.strftime("%Y-%m-%d"))

# 15. Sorting by Multiple Columns for Complex Objects (Age, then Name)
students = [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Alice", "age": 22}]
sorted_students = sorted(students, key=lambda x: (x['age'], x['name']))  # Sort by age, then name
print("Sorted by age and name (complex object):", sorted_students)

# 16. Sorting by Custom Function (Handling Complex Sorting)
students = [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 22}, {"name": "Charlie", "age": 22}]
sorted_students = sorted(students, key=lambda x: (x['age'], len(x['name'])))  # Sort by age, then length of name
print("Sorted by age, then length of name:", sorted_students)