Introdução
Organizar e manipular coleções de dados é uma tarefa fundamental na programação Python. Uma operação comum é agrupar elementos de uma lista com base em certos critérios. Este processo transforma seus dados em categorias organizadas, tornando-os mais fáceis de analisar e trabalhar.
Neste tutorial, você aprenderá como agrupar eficientemente elementos em uma lista Python usando várias técnicas. Começaremos com abordagens básicas e, gradualmente, introduziremos funções embutidas mais poderosas para este fim. Ao final deste laboratório, você terá uma compreensão prática de diferentes maneiras de agrupar dados de lista em Python.
Agrupamento Básico de Listas com Dicionários
Vamos começar entendendo o que significa agrupamento de listas e como implementar uma técnica básica de agrupamento usando dicionários Python.
O que é Agrupamento de Listas?
Agrupamento de listas é o processo de organizar elementos de uma lista em categorias com base em uma característica ou função específica. Por exemplo, você pode querer agrupar uma lista de números por serem pares ou ímpares, ou agrupar uma lista de palavras por sua primeira letra.
Usando Dicionários para Agrupamento Básico
A maneira mais direta de agrupar elementos de lista em Python é usar um dicionário:
- As chaves representam os grupos
- Os valores são listas contendo os elementos pertencentes a cada grupo
Vamos criar um exemplo simples onde agrupamos números com base em serem pares ou ímpares.
Passo 1: Crie um Arquivo Python
Primeiro, vamos criar um novo arquivo Python para escrever nosso código:
Abra a WebIDE e crie um novo arquivo chamado
group_numbers.pyno diretório/home/labex/project.Adicione o seguinte código ao arquivo:
## Basic list grouping using dictionaries
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
## Initialize empty dictionary to store our groups
even_odd_groups = {"even": [], "odd": []}
## Group numbers based on whether they are even or odd
for num in numbers:
if num % 2 == 0:
even_odd_groups["even"].append(num)
else:
even_odd_groups["odd"].append(num)
## Print the resulting groups
print("Grouping numbers by even/odd:")
print(f"Even numbers: {even_odd_groups['even']}")
print(f"Odd numbers: {even_odd_groups['odd']}")
- Salve o arquivo.
Passo 2: Execute o Script Python
Execute o script para ver os resultados:
Abra um terminal na WebIDE.
Execute o script:
python3 /home/labex/project/group_numbers.py
Você deve ver uma saída semelhante a:
Grouping numbers by even/odd:
Even numbers: [2, 4, 6, 8, 10]
Odd numbers: [1, 3, 5, 7, 9]
Passo 3: Agrupe por um Critério Mais Complexo
Agora, vamos modificar nosso script para agrupar números com base em seu resto quando divididos por 3:
- Adicione o seguinte código ao seu arquivo
group_numbers.py:
## Group numbers by remainder when divided by 3
remainder_groups = {0: [], 1: [], 2: []}
for num in numbers:
remainder = num % 3
remainder_groups[remainder].append(num)
print("\nGrouping numbers by remainder when divided by 3:")
for remainder, nums in remainder_groups.items():
print(f"Numbers with remainder {remainder}: {nums}")
Salve o arquivo.
Execute o script novamente:
python3 /home/labex/project/group_numbers.py
Agora você deve ver uma saída adicional:
Grouping numbers by remainder when divided by 3:
Numbers with remainder 0: [3, 6, 9]
Numbers with remainder 1: [1, 4, 7, 10]
Numbers with remainder 2: [2, 5, 8]
Esta técnica básica usando dicionários fornece uma maneira direta de agrupar elementos de lista. No entanto, à medida que suas necessidades de agrupamento se tornam mais complexas, Python oferece métodos mais poderosos e eficientes, que exploraremos nos próximos passos.
Usando itertools.groupby() para Agrupamento Eficiente
Agora que você entende o conceito básico de agrupamento, vamos explorar uma abordagem mais poderosa usando a função embutida itertools.groupby(). Esta função é particularmente útil ao trabalhar com dados ordenados.
Entendendo itertools.groupby()
A função groupby() do módulo itertools agrupa elementos consecutivos em um iterável com base em uma função chave. Ela retorna um iterador que produz pares de:
- O valor retornado pela função chave
- Um iterador produzindo os itens no grupo
Nota importante: groupby() apenas agrupa itens consecutivos, então os dados de entrada normalmente precisam ser ordenados primeiro.
Vamos implementar um exemplo para ver como isso funciona na prática.
Passo 1: Crie um Novo Arquivo Python
Crie um novo arquivo chamado
groupby_example.pyno diretório/home/labex/project.Adicione o seguinte código para importar o módulo necessário:
import itertools
## Sample data
words = ["apple", "banana", "avocado", "blueberry", "apricot", "blackberry"]
Passo 2: Agrupe Palavras pela Primeira Letra
Agora, vamos usar itertools.groupby() para agrupar as palavras pela sua primeira letra:
- Adicione o seguinte código ao seu arquivo
groupby_example.py:
## First, we need to sort the list by the key we'll use for grouping
## In this case, the first letter of each word
words.sort(key=lambda x: x[0])
print("Sorted words:", words)
## Now group by first letter
grouped_words = {}
for first_letter, group in itertools.groupby(words, key=lambda x: x[0]):
grouped_words[first_letter] = list(group)
## Print the resulting groups
print("\nGrouping words by first letter:")
for letter, words_group in grouped_words.items():
print(f"Words starting with '{letter}': {words_group}")
Salve o arquivo.
Execute o script:
python3 /home/labex/project/groupby_example.py
Você deve ver uma saída semelhante a:
Sorted words: ['apple', 'apricot', 'avocado', 'banana', 'blackberry', 'blueberry']
Grouping words by first letter:
Words starting with 'a': ['apple', 'apricot', 'avocado']
Words starting with 'b': ['banana', 'blackberry', 'blueberry']
Passo 3: Entendendo a Importância da Ordenação
Para demonstrar por que a ordenação é crucial ao usar groupby(), vamos adicionar outro exemplo sem ordenação:
- Adicione o seguinte código ao seu arquivo
groupby_example.py:
## Sample data (unsorted)
unsorted_words = ["apple", "banana", "avocado", "blueberry", "apricot", "blackberry"]
print("\n--- Without sorting first ---")
print("Original words:", unsorted_words)
## Try to group without sorting
unsorted_grouped = {}
for first_letter, group in itertools.groupby(unsorted_words, key=lambda x: x[0]):
unsorted_grouped[first_letter] = list(group)
print("\nGrouping without sorting:")
for letter, words_group in unsorted_grouped.items():
print(f"Words starting with '{letter}': {words_group}")
Salve o arquivo.
Execute o script novamente:
python3 /home/labex/project/groupby_example.py
Na saída, você notará que o agrupamento sem ordenação produz resultados diferentes:
--- Without sorting first ---
Original words: ['apple', 'banana', 'avocado', 'blueberry', 'apricot', 'blackberry']
Grouping without sorting:
Words starting with 'a': ['apple']
Words starting with 'b': ['banana']
Words starting with 'a': ['avocado']
Words starting with 'b': ['blueberry']
Words starting with 'a': ['apricot']
Words starting with 'b': ['blackberry']
Observe como temos múltiplos grupos com a mesma chave. Isso acontece porque groupby() apenas agrupa itens consecutivos. Quando os dados não estão ordenados, itens com a mesma chave, mas que aparecem em posições diferentes na lista, serão colocados em grupos separados.
A função itertools.groupby() é muito eficiente e faz parte da biblioteca padrão, tornando-a uma ferramenta poderosa para muitas tarefas de agrupamento. No entanto, lembre-se de que ela funciona melhor com dados ordenados.
Agrupamento com collections.defaultdict
Outra ferramenta poderosa para agrupamento em Python é a classe defaultdict do módulo collections. Essa abordagem oferece uma maneira mais limpa e eficiente de agrupar dados em comparação com o uso de dicionários regulares.
Entendendo defaultdict
Um defaultdict é uma subclasse de dicionário que inicializa automaticamente o primeiro valor para uma chave ausente. Isso elimina a necessidade de verificar se uma chave existe antes de adicionar um item a um dicionário. Para fins de agrupamento, isso significa que podemos evitar escrever código condicional para inicializar listas vazias para novos grupos.
Vamos ver como defaultdict simplifica o processo de agrupamento.
Passo 1: Crie um Novo Arquivo Python
Crie um novo arquivo chamado
defaultdict_grouping.pyno diretório/home/labex/project.Adicione o seguinte código para importar o módulo necessário e criar alguns dados de exemplo:
from collections import defaultdict
## Sample data - a list of people with their ages
people = [
{"name": "Alice", "age": 25, "city": "New York"},
{"name": "Bob", "age": 30, "city": "Boston"},
{"name": "Charlie", "age": 35, "city": "Chicago"},
{"name": "David", "age": 25, "city": "Denver"},
{"name": "Eve", "age": 30, "city": "Boston"},
{"name": "Frank", "age": 35, "city": "Chicago"},
{"name": "Grace", "age": 25, "city": "New York"}
]
Passo 2: Agrupe Pessoas por Idade
Agora, vamos usar defaultdict para agrupar pessoas por sua idade:
- Adicione o seguinte código ao seu arquivo
defaultdict_grouping.py:
## Group people by age using defaultdict
age_groups = defaultdict(list)
for person in people:
age_groups[person["age"]].append(person["name"])
## Print the resulting groups
print("Grouping people by age:")
for age, names in age_groups.items():
print(f"Age {age}: {names}")
Salve o arquivo.
Execute o script:
python3 /home/labex/project/defaultdict_grouping.py
Você deve ver uma saída semelhante a:
Grouping people by age:
Age 25: ['Alice', 'David', 'Grace']
Age 30: ['Bob', 'Eve']
Age 35: ['Charlie', 'Frank']
Passo 3: Compare com a Abordagem de Dicionário Regular
Para entender a vantagem de usar defaultdict, vamos compará-lo com a abordagem de dicionário regular:
- Adicione o seguinte código ao seu arquivo
defaultdict_grouping.py:
print("\n--- Comparison with regular dictionary ---")
## Using a regular dictionary (the conventional way)
regular_dict_groups = {}
for person in people:
age = person["age"]
name = person["name"]
## Need to check if the key exists
if age not in regular_dict_groups:
regular_dict_groups[age] = []
regular_dict_groups[age].append(name)
print("\nRegular dictionary approach:")
for age, names in regular_dict_groups.items():
print(f"Age {age}: {names}")
Salve o arquivo.
Execute o script novamente:
python3 /home/labex/project/defaultdict_grouping.py
Você notará que ambas as abordagens produzem o mesmo resultado, mas a abordagem defaultdict é mais limpa e requer menos código.
Passo 4: Agrupe por Múltiplos Critérios
Agora, vamos estender nosso exemplo para agrupar pessoas por cidade e idade:
- Adicione o seguinte código ao seu arquivo
defaultdict_grouping.py:
## Grouping by city and then by age
city_age_groups = defaultdict(lambda: defaultdict(list))
for person in people:
city = person["city"]
age = person["age"]
name = person["name"]
city_age_groups[city][age].append(name)
print("\nGrouping people by city and then by age:")
for city, age_groups in city_age_groups.items():
print(f"\nCity: {city}")
for age, names in age_groups.items():
print(f" Age {age}: {names}")
Salve o arquivo.
Execute o script novamente:
python3 /home/labex/project/defaultdict_grouping.py
Você deve ver uma saída adicional semelhante a:
Grouping people by city and then by age:
City: New York
Age 25: ['Alice', 'Grace']
City: Boston
Age 30: ['Bob', 'Eve']
City: Chicago
Age 35: ['Charlie', 'Frank']
City: Denver
Age 25: ['David']
Essa abordagem aninhada de defaultdict permite hierarquias de agrupamento mais complexas com código mínimo. O defaultdict é particularmente útil quando você não conhece todas as chaves do grupo com antecedência, pois ele cria novos grupos automaticamente quando necessário.
Aplicação Prática: Analisando Dados com Técnicas de Agrupamento
Agora que você entende vários métodos para agrupar dados, vamos aplicar essas técnicas para resolver um problema do mundo real: analisar um conjunto de dados de registros de alunos. Usaremos diferentes métodos de agrupamento para extrair informações úteis dos dados.
Configurando o Conjunto de Dados de Exemplo
Primeiro, vamos criar nosso conjunto de dados de registros de alunos:
Crie um novo arquivo chamado
student_analysis.pyno diretório/home/labex/project.Adicione o seguinte código para configurar os dados de exemplo:
import itertools
from collections import defaultdict
## Sample student data
students = [
{"id": 1, "name": "Emma", "grade": "A", "subject": "Math", "score": 95},
{"id": 2, "name": "Noah", "grade": "B", "subject": "Math", "score": 82},
{"id": 3, "name": "Olivia", "grade": "A", "subject": "Science", "score": 90},
{"id": 4, "name": "Liam", "grade": "C", "subject": "Math", "score": 75},
{"id": 5, "name": "Ava", "grade": "B", "subject": "Science", "score": 88},
{"id": 6, "name": "William", "grade": "A", "subject": "History", "score": 96},
{"id": 7, "name": "Sophia", "grade": "B", "subject": "History", "score": 85},
{"id": 8, "name": "James", "grade": "C", "subject": "Science", "score": 72},
{"id": 9, "name": "Isabella", "grade": "A", "subject": "Math", "score": 91},
{"id": 10, "name": "Benjamin", "grade": "B", "subject": "History", "score": 84}
]
print("Student Records:")
for student in students:
print(f"ID: {student['id']}, Name: {student['name']}, Subject: {student['subject']}, Grade: {student['grade']}, Score: {student['score']}")
- Salve o arquivo.
Usando defaultdict para Agrupar Alunos por Disciplina
Vamos analisar quais alunos estão cursando cada disciplina:
- Adicione o seguinte código ao seu arquivo
student_analysis.py:
print("\n--- Students Grouped by Subject ---")
## Group students by subject using defaultdict
subject_groups = defaultdict(list)
for student in students:
subject_groups[student["subject"]].append(student["name"])
## Print students by subject
for subject, names in subject_groups.items():
print(f"{subject}: {names}")
- Salve o arquivo.
Calculando as Médias de Notas por Disciplina
Vamos calcular a média de notas para cada disciplina:
- Adicione o seguinte código ao seu arquivo
student_analysis.py:
print("\n--- Average Scores by Subject ---")
## Calculate average scores for each subject
subject_scores = defaultdict(list)
for student in students:
subject_scores[student["subject"]].append(student["score"])
## Calculate and print averages
for subject, scores in subject_scores.items():
average = sum(scores) / len(scores)
print(f"{subject} Average: {average:.2f}")
- Salve o arquivo.
Usando itertools.groupby() para Analisar as Notas
Agora, vamos usar itertools.groupby() para analisar a distribuição das notas:
- Adicione o seguinte código ao seu arquivo
student_analysis.py:
print("\n--- Grade Distribution (using itertools.groupby) ---")
## Sort students by grade first
sorted_students = sorted(students, key=lambda x: x["grade"])
## Group and count students by grade
grade_counts = {}
for grade, group in itertools.groupby(sorted_students, key=lambda x: x["grade"]):
grade_counts[grade] = len(list(group))
## Print grade distribution
for grade, count in grade_counts.items():
print(f"Grade {grade}: {count} students")
- Salve o arquivo.
Combinando Técnicas: Análise Avançada
Finalmente, vamos realizar uma análise mais complexa combinando nossas técnicas de agrupamento:
- Adicione o seguinte código ao seu arquivo
student_analysis.py:
print("\n--- Advanced Analysis: Grade Distribution by Subject ---")
## Group by subject and grade
subject_grade_counts = defaultdict(lambda: defaultdict(int))
for student in students:
subject = student["subject"]
grade = student["grade"]
subject_grade_counts[subject][grade] += 1
## Print detailed grade distribution by subject
for subject, grades in subject_grade_counts.items():
print(f"\n{subject}:")
for grade, count in grades.items():
print(f" Grade {grade}: {count} students")
Salve o arquivo.
Execute o script completo:
python3 /home/labex/project/student_analysis.py
Você deve ver uma análise abrangente dos dados dos alunos, incluindo:
- Registros de alunos
- Alunos agrupados por disciplina
- Médias de notas por disciplina
- Distribuição geral das notas
- Distribuição das notas por disciplina
Este exemplo demonstra como diferentes técnicas de agrupamento podem ser combinadas para realizar análises de dados complexas com código relativamente simples. Cada abordagem tem seus pontos fortes:
defaultdicté excelente para agrupamento simples sem ter que verificar a existência da chaveitertools.groupby()é eficiente para trabalhar com dados ordenados- A combinação de técnicas permite o agrupamento em vários níveis e análises complexas
A seleção da técnica de agrupamento correta depende de suas necessidades específicas e da estrutura de seus dados.
Resumo
Neste tutorial, você aprendeu vários métodos eficientes para agrupar listas em Python:
Agrupamento Básico com Dicionário: Você começou com uma abordagem fundamental usando dicionários regulares para criar grupos com base em critérios específicos.
itertools.groupby(): Você explorou esta função embutida que agrupa eficientemente elementos consecutivos em dados ordenados, compreendendo suas vantagens e limitações.
collections.defaultdict: Você usou esta conveniente subclasse de dicionário que lida automaticamente com chaves ausentes, tornando seu código de agrupamento mais limpo e conciso.
Análise Prática de Dados: Você aplicou essas técnicas para analisar um conjunto de dados, vendo como elas podem ser usadas individualmente e em combinação para extrair insights significativos.
Cada um desses métodos tem seus pontos fortes e casos de uso ideais:
- Use dicionários básicos para agrupamento simples quando a clareza é mais importante que a concisão
- Use
itertools.groupby()quando seus dados estiverem ordenados ou puderem ser ordenados pela chave de agrupamento - Use
defaultdictquando você deseja um código limpo e conciso e não conhece todas as chaves do grupo com antecedência - Combine técnicas para agrupamento e análise complexos e de vários níveis
Ao dominar essas técnicas de agrupamento, você adicionou ferramentas poderosas ao seu kit de ferramentas de programação Python que o ajudarão a organizar, analisar e manipular dados de forma mais eficiente.



