Como usar uma função lambda para ordenação personalizada em Python

PythonBeginner
Pratique Agora

Introdução

As funções lambda do Python oferecem uma maneira concisa e poderosa de realizar operações de ordenação personalizadas. Neste tutorial, exploraremos como usar funções lambda para ordenar dados em Python, abrindo novas possibilidades para manipulação e análise de dados. Ao final, você terá uma sólida compreensão de como aproveitar as funções lambda para ordenação personalizada e será capaz de aplicar essas técnicas aos seus próprios projetos Python.

Compreendendo as Funções Lambda

No Python, uma função lambda é uma pequena função anônima definida com a palavra-chave lambda. Ao contrário das funções regulares que usam a palavra-chave def, as funções lambda podem ser criadas inline e não precisam de uma definição separada.

Vamos criar um novo arquivo Python para explorar as funções lambda. Abra a WebIDE e crie um novo arquivo chamado basic_lambda.py no diretório /home/labex/project/lambda_sorting.

Adicione o seguinte código a 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)}")

Agora, vamos executar este arquivo no terminal:

python3 basic_lambda.py

Você deve ver uma saída como esta:

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

As funções lambda são especialmente úteis quando você precisa de uma função simples por um curto período, particularmente ao usar funções como map(), filter() ou sorted(). Vamos criar outro exemplo para ver lambdas em ação com a função map().

Crie um novo arquivo chamado lambda_with_map.py com o seguinte conteúdo:

## 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}")

Execute este arquivo:

python3 lambda_with_map.py

Você deve ver:

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

Compreender as funções lambda é essencial antes de aplicá-las à ordenação. No próximo passo, exploraremos como usar funções lambda com as funções de ordenação do Python.

Ordenação Básica com Funções Lambda

O Python oferece duas maneiras principais de ordenar coleções: a função sorted() e o método .sort() para listas. Podemos usar funções lambda com ambas para criar lógica de ordenação personalizada.

Vamos criar um novo arquivo chamado basic_sorting.py para explorar a ordenação básica com funções lambda:

## 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}")

Execute este arquivo:

python3 basic_sorting.py

Você deve ver uma saída como:

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']

O parâmetro key em sorted() recebe uma função que transforma cada item antes da comparação. As funções lambda fornecem uma maneira concisa de criar essas transformações.

Agora, vamos tentar ordenar com estruturas de dados mais complexas. Crie um arquivo chamado 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]}")

Execute este arquivo:

python3 sorting_tuples.py

Você deve ver os alunos ordenados de diferentes maneiras:

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

No próximo passo, exploraremos técnicas de ordenação mais avançadas usando funções lambda.

Técnicas Avançadas de Ordenação

Agora que entendemos o básico, vamos explorar técnicas de ordenação mais avançadas usando funções lambda.

Ordenando Dicionários

Dicionários são uma estrutura de dados comum no Python, e frequentemente precisamos ordenar listas de dicionários. Crie um arquivo chamado 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']}")

Execute este arquivo:

python3 sorting_dictionaries.py

Você deve ver os produtos ordenados de diferentes maneiras:

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

Ordenação Multi-Nível

Às vezes, precisamos ordenar itens usando múltiplos critérios. Por exemplo, podemos querer ordenar alunos primeiro por nota e, em seguida, por idade para aqueles com a mesma nota.

Crie um arquivo chamado 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']}")

Execute este arquivo:

python3 multi_level_sorting.py

Você deve ver:

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

Observe como usamos tuplas dentro da função lambda para definir múltiplos critérios de ordenação. O primeiro elemento na tupla é a chave de ordenação primária, e os elementos subsequentes são usados para desempate.

Usamos um sinal negativo -student["age"] para ordenar por idade em ordem decrescente. Essa técnica é útil quando você deseja ordenar numericamente em ordem inversa.

Ordenando Objetos Personalizados

Vamos criar um exemplo final para mostrar como ordenar objetos de classe personalizados. Crie um arquivo chamado 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}")

Execute este arquivo:

python3 sorting_objects.py

Você deve ver:

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)

Este exemplo demonstra como as funções lambda podem ser usadas para ordenar objetos personalizados acessando seus atributos diretamente.

Aplicação de Ordenação no Mundo Real

Agora, vamos aplicar o que aprendemos a um cenário de análise de dados mais realista. Criaremos um programa que analisa um conjunto de dados de livros e permite a ordenação por diferentes critérios.

Crie um arquivo chamado 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}")

Execute este arquivo:

python3 book_analyzer.py

Você verá os livros ordenados de várias maneiras:

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]

Este exemplo demonstra como as funções lambda podem ser usadas em uma aplicação real para fornecer recursos de ordenação flexíveis. Observe como armazenamos as funções lambda junto com suas descrições em um dicionário, o que facilitaria a adição de mais opções de ordenação em uma aplicação real.

Vamos criar uma versão interativa onde o usuário pode escolher uma opção de ordenação. Crie um arquivo chamado 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.")

Execute esta versão interativa:

python3 interactive_book_sorter.py

Isso permitirá que você selecione diferentes opções de ordenação e veja os resultados. Quando terminar, digite "0" para sair do programa.

A aplicação interativa demonstra como as funções lambda facilitam a implementação de várias opções de ordenação em uma aplicação real. Cada opção de ordenação é simplesmente uma função lambda que extrai as informações relevantes do dicionário do livro.

Resumo

Parabéns por concluir este tutorial sobre o uso de funções lambda para ordenação personalizada em Python. Você aprendeu:

  1. Os fundamentos das funções lambda e como elas diferem das funções regulares
  2. Como usar funções lambda com as funções de ordenação do Python (sorted() e .sort())
  3. Técnicas para ordenar diferentes estruturas de dados:
    • Listas de valores simples
    • Listas de tuplas
    • Listas de dicionários
    • Objetos personalizados
  4. Ordenação multi-nível usando tuplas em funções lambda
  5. Como aplicar funções lambda em uma aplicação de análise de dados do mundo real

Essas habilidades serão incrivelmente úteis para processamento, análise e manipulação de dados em seus futuros projetos Python. As funções lambda fornecem uma maneira concisa e poderosa de personalizar o comportamento de ordenação, tornando seu código mais expressivo e fácil de manter.

À medida que você continua sua jornada em Python, descobrirá que as funções lambda são úteis não apenas para ordenação, mas também para outras funções de ordem superior como map(), filter() e reduce(). As técnicas que você aprendeu neste tutorial servirão como uma base sólida para essas aplicações mais avançadas.