Как использовать лямбда-функции для пользовательской сортировки в Python

PythonBeginner
Практиковаться сейчас

Введение

Лямбда-функции (lambda functions) в Python предоставляют лаконичный и мощный способ выполнения пользовательских операций сортировки. В этом руководстве мы рассмотрим, как использовать лямбда-функции для сортировки данных в Python, открывая новые возможности для манипулирования данными и их анализа. К концу вы получите прочное понимание использования лямбда-функций для пользовательской сортировки и сможете применять эти методы в своих собственных проектах на Python.

Понимание лямбда-функций

В Python лямбда-функция (lambda function) — это небольшая анонимная функция, определенная с помощью ключевого слова lambda. В отличие от обычных функций, использующих ключевое слово def, лямбда-функции могут быть созданы встраиваемым способом и не требуют отдельного определения.

Давайте создадим новый файл Python, чтобы изучить лямбда-функции. Откройте WebIDE и создайте новый файл с именем basic_lambda.py в каталоге /home/labex/project/lambda_sorting.

Добавьте следующий код в basic_lambda.py:

## Define a regular function
def square_function(x):
    return x * x

## The equivalent lambda function
square_lambda = lambda x: x * x

## Test both functions
number = 5
print(f"Using regular function: {number}² = {square_function(number)}")
print(f"Using lambda function: {number}² = {square_lambda(number)}")

## Lambda with multiple arguments
add = lambda x, y: x + y
print(f"{3} + {4} = {add(3, 4)}")

Теперь давайте запустим этот файл в терминале:

python3 basic_lambda.py

Вы должны увидеть вывод, подобный этому:

Using regular function: 5² = 25
Using lambda function: 5² = 25
3 + 4 = 7

Лямбда-функции особенно полезны, когда вам нужна простая функция на короткий период времени, особенно при использовании таких функций, как map(), filter() или sorted(). Давайте создадим еще один пример, чтобы увидеть лямбда-функции в действии с функцией map().

Создайте новый файл с именем lambda_with_map.py со следующим содержимым:

## Using lambda with map() to apply a function to all items in a list
numbers = [1, 2, 3, 4, 5]

## Square all numbers using map with a lambda function
squared_numbers = list(map(lambda x: x * x, numbers))

print(f"Original numbers: {numbers}")
print(f"Squared numbers: {squared_numbers}")

## Double all numbers using map with a lambda function
doubled_numbers = list(map(lambda x: x * 2, numbers))
print(f"Doubled numbers: {doubled_numbers}")

Запустите этот файл:

python3 lambda_with_map.py

Вы должны увидеть:

Original numbers: [1, 2, 3, 4, 5]
Squared numbers: [1, 4, 9, 16, 25]
Doubled numbers: [2, 4, 6, 8, 10]

Понимание лямбда-функций необходимо, прежде чем мы применим их к сортировке. На следующем шаге мы рассмотрим, как использовать лямбда-функции с функциями сортировки Python.

Базовая сортировка с лямбда-функциями

Python предоставляет два основных способа сортировки коллекций: функцию sorted() и метод .sort() для списков. Мы можем использовать лямбда-функции с обоими для создания пользовательской логики сортировки.

Давайте создадим новый файл с именем basic_sorting.py, чтобы изучить базовую сортировку с лямбда-функциями:

## Basic sorting examples
fruits = ["apple", "banana", "cherry", "date", "elderberry", "fig"]

## Sort alphabetically (default behavior)
alphabetical = sorted(fruits)
print(f"Alphabetical order: {alphabetical}")

## Sort by length using a lambda function
by_length = sorted(fruits, key=lambda x: len(x))
print(f"Sorted by length: {by_length}")

## Sort by the last character
by_last_char = sorted(fruits, key=lambda x: x[-1])
print(f"Sorted by last character: {by_last_char}")

## Sort in reverse order (longest to shortest)
longest_first = sorted(fruits, key=lambda x: len(x), reverse=True)
print(f"Longest to shortest: {longest_first}")

Запустите этот файл:

python3 basic_sorting.py

Вы должны увидеть вывод, подобный:

Alphabetical order: ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig']
Sorted by length: ['fig', 'date', 'apple', 'cherry', 'banana', 'elderberry']
Sorted by last character: ['banana', 'apple', 'date', 'fig', 'cherry', 'elderberry']
Longest to shortest: ['elderberry', 'banana', 'cherry', 'apple', 'date', 'fig']

Параметр key в sorted() принимает функцию, которая преобразует каждый элемент перед сравнением. Лямбда-функции предоставляют лаконичный способ создания этих преобразований.

Теперь давайте попробуем сортировку с более сложными структурами данных. Создайте файл с именем sorting_tuples.py:

## Sorting lists of tuples
students = [
    ("Alice", 21, 85),
    ("Bob", 19, 90),
    ("Charlie", 22, 78),
    ("David", 20, 92),
    ("Eve", 18, 88)
]

print("Original student data:")
for student in students:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

## Sort by name (first element in tuple)
by_name = sorted(students, key=lambda student: student[0])
print("\nSorted by name:")
for student in by_name:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

## Sort by age (second element)
by_age = sorted(students, key=lambda student: student[1])
print("\nSorted by age:")
for student in by_age:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

## Sort by grade (third element)
by_grade = sorted(students, key=lambda student: student[2], reverse=True)
print("\nSorted by grade (highest first):")
for student in by_grade:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

Запустите этот файл:

python3 sorting_tuples.py

Вы должны увидеть студентов, отсортированных разными способами:

Original student data:
  Alice: age 21, grade 85
  Bob: age 19, grade 90
  Charlie: age 22, grade 78
  David: age 20, grade 92
  Eve: age 18, grade 88

Sorted by name:
  Alice: age 21, grade 85
  Bob: age 19, grade 90
  Charlie: age 22, grade 78
  David: age 20, grade 92
  Eve: age 18, grade 88

Sorted by age:
  Eve: age 18, grade 88
  Bob: age 19, grade 90
  David: age 20, grade 92
  Alice: age 21, grade 85
  Charlie: age 22, grade 78

Sorted by grade (highest first):
  David: age 20, grade 92
  Bob: age 19, grade 90
  Eve: age 18, grade 88
  Alice: age 21, grade 85
  Charlie: age 22, grade 78

На следующем шаге мы рассмотрим более продвинутые методы сортировки с использованием лямбда-функций.

Продвинутые методы сортировки

Теперь, когда мы понимаем основы, давайте рассмотрим более продвинутые методы сортировки с использованием лямбда-функций.

Сортировка словарей

Словари — распространенная структура данных в Python, и нам часто нужно сортировать списки словарей. Создайте файл с именем sorting_dictionaries.py:

## Sorting lists of dictionaries
products = [
    {"name": "Laptop", "price": 999.99, "stock": 25},
    {"name": "Phone", "price": 499.50, "stock": 42},
    {"name": "Tablet", "price": 299.75, "stock": 15},
    {"name": "Headphones", "price": 149.99, "stock": 34},
    {"name": "Mouse", "price": 24.99, "stock": 55}
]

## Print original products
print("Original product list:")
for product in products:
    print(f"  {product['name']}: ${product['price']}, Stock: {product['stock']}")

## Sort by price (lowest to highest)
by_price = sorted(products, key=lambda product: product["price"])
print("\nSorted by price (lowest to highest):")
for product in by_price:
    print(f"  {product['name']}: ${product['price']}, Stock: {product['stock']}")

## Sort by stock (highest to lowest)
by_stock = sorted(products, key=lambda product: product["stock"], reverse=True)
print("\nSorted by stock (highest to lowest):")
for product in by_stock:
    print(f"  {product['name']}: ${product['price']}, Stock: {product['stock']}")

## Sort by name (alphabetically)
by_name = sorted(products, key=lambda product: product["name"])
print("\nSorted by name:")
for product in by_name:
    print(f"  {product['name']}: ${product['price']}, Stock: {product['stock']}")

Запустите этот файл:

python3 sorting_dictionaries.py

Вы должны увидеть продукты, отсортированные разными способами:

Original product list:
  Laptop: $999.99, Stock: 25
  Phone: $499.5, Stock: 42
  Tablet: $299.75, Stock: 15
  Headphones: $149.99, Stock: 34
  Mouse: $24.99, Stock: 55

Sorted by price (lowest to highest):
  Mouse: $24.99, Stock: 55
  Headphones: $149.99, Stock: 34
  Tablet: $299.75, Stock: 15
  Phone: $499.5, Stock: 42
  Laptop: $999.99, Stock: 25

Sorted by stock (highest to lowest):
  Mouse: $24.99, Stock: 55
  Phone: $499.5, Stock: 42
  Headphones: $149.99, Stock: 34
  Laptop: $999.99, Stock: 25
  Tablet: $299.75, Stock: 15

Sorted by name:
  Headphones: $149.99, Stock: 34
  Laptop: $999.99, Stock: 25
  Mouse: $24.99, Stock: 55
  Phone: $499.5, Stock: 42
  Tablet: $299.75, Stock: 15

Многоуровневая сортировка

Иногда нам нужно сортировать элементы, используя несколько критериев. Например, мы можем захотеть отсортировать студентов сначала по оценке, а затем по возрасту для тех, у кого одинаковая оценка.

Создайте файл с именем multi_level_sorting.py:

## Multi-level sorting example
students = [
    {"name": "Alice", "grade": "A", "age": 21},
    {"name": "Bob", "grade": "B", "age": 19},
    {"name": "Charlie", "grade": "A", "age": 22},
    {"name": "David", "grade": "C", "age": 20},
    {"name": "Eve", "grade": "B", "age": 18},
    {"name": "Frank", "grade": "A", "age": 19}
]

print("Original student list:")
for student in students:
    print(f"  {student['name']}: Grade {student['grade']}, Age {student['age']}")

## Sort by grade (A to C), then by age (youngest to oldest)
## To sort by grade, we create a dictionary for grade priorities
grade_priority = {"A": 1, "B": 2, "C": 3}  ## A is highest priority (lowest number)

by_grade_then_age = sorted(students,
                           key=lambda student: (grade_priority[student["grade"]], student["age"]))

print("\nSorted by grade (A first), then by age (youngest first):")
for student in by_grade_then_age:
    print(f"  {student['name']}: Grade {student['grade']}, Age {student['age']}")

## Sort by age (oldest to youngest), then by name (alphabetically)
by_age_then_name = sorted(students,
                          key=lambda student: (-student["age"], student["name"]))

print("\nSorted by age (oldest first), then by name:")
for student in by_age_then_name:
    print(f"  {student['name']}: Grade {student['grade']}, Age {student['age']}")

Запустите этот файл:

python3 multi_level_sorting.py

Вы должны увидеть:

Original student list:
  Alice: Grade A, Age 21
  Bob: Grade B, Age 19
  Charlie: Grade A, Age 22
  David: Grade C, Age 20
  Eve: Grade B, Age 18
  Frank: Grade A, Age 19

Sorted by grade (A first), then by age (youngest first):
  Frank: Grade A, Age 19
  Alice: Grade A, Age 21
  Charlie: Grade A, Age 22
  Eve: Grade B, Age 18
  Bob: Grade B, Age 19
  David: Grade C, Age 20

Sorted by age (oldest first), then by name:
  Charlie: Grade A, Age 22
  Alice: Grade A, Age 21
  David: Grade C, Age 20
  Bob: Grade B, Age 19
  Frank: Grade A, Age 19
  Eve: Grade B, Age 18

Обратите внимание, как мы использовали кортежи внутри лямбда-функции для определения нескольких критериев сортировки. Первый элемент в кортеже является основным ключом сортировки, а последующие элементы используются для разрешения коллизий.

Мы использовали отрицательный знак -student["age"] для сортировки по возрасту в порядке убывания. Эта техника полезна, когда вы хотите сортировать в числовом порядке в обратном порядке.

Сортировка пользовательских объектов

Давайте создадим последний пример, чтобы показать, как сортировать объекты пользовательских классов. Создайте файл с именем sorting_objects.py:

## Sorting objects of a custom class
class Person:
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height  ## in cm

    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age}, height={self.height}cm)"

## Create a list of Person objects
people = [
    Person("Alice", 25, 165),
    Person("Bob", 30, 180),
    Person("Charlie", 22, 175),
    Person("David", 35, 170),
    Person("Eve", 28, 160)
]

print("Original list of people:")
for person in people:
    print(f"  {person}")

## Sort by age
by_age = sorted(people, key=lambda person: person.age)
print("\nSorted by age:")
for person in by_age:
    print(f"  {person}")

## Sort by height
by_height = sorted(people, key=lambda person: person.height)
print("\nSorted by height:")
for person in by_height:
    print(f"  {person}")

## Sort by name length, then by age
by_name_length_then_age = sorted(people, key=lambda person: (len(person.name), person.age))
print("\nSorted by name length, then by age:")
for person in by_name_length_then_age:
    print(f"  {person}")

Запустите этот файл:

python3 sorting_objects.py

Вы должны увидеть:

Original list of people:
  Person(name='Alice', age=25, height=165cm)
  Person(name='Bob', age=30, height=180cm)
  Person(name='Charlie', age=22, height=175cm)
  Person(name='David', age=35, height=170cm)
  Person(name='Eve', age=28, height=160cm)

Sorted by age:
  Person(name='Charlie', age=22, height=175cm)
  Person(name='Alice', age=25, height=165cm)
  Person(name='Eve', age=28, height=160cm)
  Person(name='Bob', age=30, height=180cm)
  Person(name='David', age=35, height=170cm)

Sorted by height:
  Person(name='Eve', age=28, height=160cm)
  Person(name='Alice', age=25, height=165cm)
  Person(name='David', age=35, height=170cm)
  Person(name='Charlie', age=22, height=175cm)
  Person(name='Bob', age=30, height=180cm)

Sorted by name length, then by age:
  Person(name='Bob', age=30, height=180cm)
  Person(name='Eve', age=28, height=160cm)
  Person(name='Alice', age=25, height=165cm)
  Person(name='David', age=35, height=170cm)
  Person(name='Charlie', age=22, height=175cm)

Этот пример демонстрирует, как лямбда-функции можно использовать для сортировки пользовательских объектов путем прямого доступа к их атрибутам.

Реальное применение сортировки

Теперь давайте применим то, что мы узнали, к более реалистичному сценарию анализа данных. Мы создадим программу, которая анализирует набор данных о книгах и позволяет сортировать по различным критериям.

Создайте файл с именем book_analyzer.py:

## Book data analysis application
books = [
    {
        "title": "The Great Gatsby",
        "author": "F. Scott Fitzgerald",
        "year": 1925,
        "pages": 180,
        "rating": 4.2,
        "genres": ["Classic", "Fiction"]
    },
    {
        "title": "To Kill a Mockingbird",
        "author": "Harper Lee",
        "year": 1960,
        "pages": 281,
        "rating": 4.3,
        "genres": ["Classic", "Fiction", "Drama"]
    },
    {
        "title": "1984",
        "author": "George Orwell",
        "year": 1949,
        "pages": 328,
        "rating": 4.2,
        "genres": ["Dystopian", "Fiction", "Political"]
    },
    {
        "title": "The Hobbit",
        "author": "J.R.R. Tolkien",
        "year": 1937,
        "pages": 310,
        "rating": 4.4,
        "genres": ["Fantasy", "Adventure"]
    },
    {
        "title": "Harry Potter and the Sorcerer's Stone",
        "author": "J.K. Rowling",
        "year": 1997,
        "pages": 309,
        "rating": 4.5,
        "genres": ["Fantasy", "Adventure", "Young Adult"]
    },
    {
        "title": "The Catcher in the Rye",
        "author": "J.D. Salinger",
        "year": 1951,
        "pages": 214,
        "rating": 3.8,
        "genres": ["Fiction", "Coming of Age"]
    }
]

def print_books(book_list, heading):
    """Helper function to print books in a formatted way"""
    print(f"\n{heading}")
    print("-" * 80)
    for book in book_list:
        genres = ", ".join(book["genres"])
        print(f"{book['title']} by {book['author']} ({book['year']}) - {book['pages']} pages")
        print(f"  Rating: {book['rating']}, Genres: {genres}")
    print("-" * 80)

## Print the original list
print_books(books, "Original Book List")

## Sort books by different criteria
sort_options = {
    "1": ("Title (A-Z)", lambda b: b["title"]),
    "2": ("Author (A-Z)", lambda b: b["author"]),
    "3": ("Publication Year (Oldest First)", lambda b: b["year"]),
    "4": ("Publication Year (Newest First)", lambda b: -b["year"]),
    "5": ("Rating (Highest First)", lambda b: -b["rating"]),
    "6": ("Number of Pages (Lowest First)", lambda b: b["pages"]),
    "7": ("Number of Genres", lambda b: len(b["genres"])),
}

## Show sorting options
print("\nSorting Options:")
for key, (description, _) in sort_options.items():
    print(f"{key}. {description}")

## Automatically show all sorting examples for this tutorial
for option, (description, sort_key) in sort_options.items():
    sorted_books = sorted(books, key=sort_key)
    print_books(sorted_books, f"Books Sorted by {description}")

Запустите этот файл:

python3 book_analyzer.py

Вы увидите книги, отсортированные различными способами:

Original Book List
--------------------------------------------------------------------------------
The Great Gatsby by F. Scott Fitzgerald (1925) - 180 pages
  Rating: 4.2, Genres: Classic, Fiction
To Kill a Mockingbird by Harper Lee (1960) - 281 pages
  Rating: 4.3, Genres: Classic, Fiction, Drama
1984 by George Orwell (1949) - 328 pages
  Rating: 4.2, Genres: Dystopian, Fiction, Political
The Hobbit by J.R.R. Tolkien (1937) - 310 pages
  Rating: 4.4, Genres: Fantasy, Adventure
Harry Potter and the Sorcerer's Stone by J.K. Rowling (1997) - 309 pages
  Rating: 4.5, Genres: Fantasy, Adventure, Young Adult
The Catcher in the Rye by J.D. Salinger (1951) - 214 pages
  Rating: 3.8, Genres: Fiction, Coming of Age
--------------------------------------------------------------------------------

Sorting Options:
1. Title (A-Z)
2. Author (A-Z)
3. Publication Year (Oldest First)
4. Publication Year (Newest First)
5. Rating (Highest First)
6. Number of Pages (Lowest First)
7. Number of Genres

Books Sorted by Title (A-Z)
...

[Output continues with all the different sorting examples]

Этот пример демонстрирует, как лямбда-функции можно использовать в реальном приложении для обеспечения гибких возможностей сортировки. Обратите внимание, как мы хранили лямбда-функции вместе с их описаниями в словаре, что упрощает добавление дополнительных параметров сортировки в реальном приложении.

Давайте создадим интерактивную версию, где пользователь сможет выбрать параметр сортировки. Создайте файл с именем interactive_book_sorter.py:

## Interactive book sorter application
books = [
    {
        "title": "The Great Gatsby",
        "author": "F. Scott Fitzgerald",
        "year": 1925,
        "pages": 180,
        "rating": 4.2,
        "genres": ["Classic", "Fiction"]
    },
    {
        "title": "To Kill a Mockingbird",
        "author": "Harper Lee",
        "year": 1960,
        "pages": 281,
        "rating": 4.3,
        "genres": ["Classic", "Fiction", "Drama"]
    },
    {
        "title": "1984",
        "author": "George Orwell",
        "year": 1949,
        "pages": 328,
        "rating": 4.2,
        "genres": ["Dystopian", "Fiction", "Political"]
    },
    {
        "title": "The Hobbit",
        "author": "J.R.R. Tolkien",
        "year": 1937,
        "pages": 310,
        "rating": 4.4,
        "genres": ["Fantasy", "Adventure"]
    },
    {
        "title": "Harry Potter and the Sorcerer's Stone",
        "author": "J.K. Rowling",
        "year": 1997,
        "pages": 309,
        "rating": 4.5,
        "genres": ["Fantasy", "Adventure", "Young Adult"]
    },
    {
        "title": "The Catcher in the Rye",
        "author": "J.D. Salinger",
        "year": 1951,
        "pages": 214,
        "rating": 3.8,
        "genres": ["Fiction", "Coming of Age"]
    }
]

def print_books(book_list, heading):
    """Helper function to print books in a formatted way"""
    print(f"\n{heading}")
    print("-" * 80)
    for book in book_list:
        genres = ", ".join(book["genres"])
        print(f"{book['title']} by {book['author']} ({book['year']}) - {book['pages']} pages")
        print(f"  Rating: {book['rating']}, Genres: {genres}")
    print("-" * 80)

## Define our sorting options
sort_options = {
    "1": ("Title (A-Z)", lambda b: b["title"]),
    "2": ("Author (A-Z)", lambda b: b["author"]),
    "3": ("Publication Year (Oldest First)", lambda b: b["year"]),
    "4": ("Publication Year (Newest First)", lambda b: -b["year"]),
    "5": ("Rating (Highest First)", lambda b: -b["rating"]),
    "6": ("Number of Pages (Lowest First)", lambda b: b["pages"]),
    "7": ("Number of Genres", lambda b: len(b["genres"])),
}

## Print the original list
print_books(books, "Book Catalog")

while True:
    ## Show sorting options
    print("\nHow would you like to sort the books?")
    for key, (description, _) in sort_options.items():
        print(f"{key}. {description}")
    print("0. Exit")

    choice = input("\nEnter your choice (0-7): ")

    if choice == "0":
        print("Thank you for using the Book Sorter. Goodbye!")
        break
    elif choice in sort_options:
        description, sort_key = sort_options[choice]
        sorted_books = sorted(books, key=sort_key)
        print_books(sorted_books, f"Books Sorted by {description}")
    else:
        print("Invalid choice. Please try again.")

Запустите эту интерактивную версию:

python3 interactive_book_sorter.py

Это позволит вам выбрать различные параметры сортировки и увидеть результаты. Когда закончите, введите "0", чтобы выйти из программы.

Интерактивное приложение демонстрирует, как лямбда-функции упрощают реализацию различных параметров сортировки в реальном приложении. Каждый параметр сортировки — это просто лямбда-функция, которая извлекает соответствующую информацию из словаря книги.

Резюме

Поздравляем с завершением этого руководства по использованию лямбда-функций для пользовательской сортировки в Python. Вы узнали:

  1. Основы лямбда-функций и их отличия от обычных функций
  2. Как использовать лямбда-функции с функциями сортировки Python (sorted() и .sort())
  3. Методы сортировки различных структур данных:
    • Списки простых значений
    • Списки кортежей
    • Списки словарей
    • Пользовательские объекты
  4. Многоуровневую сортировку с использованием кортежей в лямбда-функциях
  5. Как применять лямбда-функции в реальном приложении для анализа данных

Эти навыки будут невероятно полезны для обработки, анализа и манипулирования данными в ваших будущих проектах на Python. Лямбда-функции предоставляют краткий и мощный способ настройки поведения сортировки, делая ваш код более выразительным и простым в обслуживании.

Продолжая свой путь в Python, вы обнаружите, что лямбда-функции полезны не только для сортировки, но и для других функций высшего порядка, таких как map(), filter() и reduce(). Методы, которые вы изучили в этом руководстве, послужат прочной основой для этих более продвинутых приложений.