0%
Estruturas de dados em Python: listas, tuplas, dicionários e conjuntos

Estruturas de dados

Organize e manipule seus dados com eficiência

10-15 min

Estruturas de dados em Python: listas, tuplas, dicionários e conjuntos

As estruturas de dados são formatos especializados para organizar, armazenar e manipular informações. O Python possui várias estruturas de dados nativas que facilitam o gerenciamento de coleções de elementos. Neste tutorial, vamos explorar as quatro principais estruturas de dados do Python: listas, tuplas, dicionários e conjuntos.

Entender essas estruturas e saber quando usar cada uma delas é essencial para escrever código Python eficiente e elegante.

Listas

As listas são uma das estruturas de dados mais versáteis e usadas com mais frequência em Python. Uma lista é uma coleção ordenada e mutável de elementos.

Criação de listas

# Lista vazia
ma_liste = []

# Lista com elementos
nombres = [1, 2, 3, 4, 5]
fruits = ["pomme", "banane", "orange"]
mixte = [1, "hello", 3.14, True]  # Pode conter diferentes tipos

# Criação com a função list()
caracteres = list("Python")  # ['P', 'y', 't', 'h', 'o', 'n']

Acesso aos elementos de uma lista

Os elementos de uma lista são indexados a partir de 0.

fruits = ["pomme", "banane", "orange", "fraise", "kiwi"]

# Acesso por índice positivo (a partir do início)
premier_fruit = fruits[0]  # "pomme"
troisieme_fruit = fruits[2]  # "orange"

# Acesso por índice negativo (a partir do fim)
dernier_fruit = fruits[-1]  # "kiwi"
avant_dernier = fruits[-2]  # "fraise"

# Fatiamento (slicing)
deux_premiers = fruits[0:2]  # ["pomme", "banane"]
du_deuxieme_au_quatrieme = fruits[1:4]  # ["banane", "orange", "fraise"]
tous_sauf_premier = fruits[1:]  # ["banane", "orange", "fraise", "kiwi"]
trois_premiers = fruits[:3]  # ["pomme", "banane", "orange"]

Modificação de listas

fruits = ["pomme", "banane", "orange"]

# Modificação de um elemento
fruits[1] = "poire"  # ["pomme", "poire", "orange"]

# Adição de elementos
fruits.append("fraise")  # Adiciona ao final: ["pomme", "poire", "orange", "fraise"]
fruits.insert(1, "kiwi")  # Insere no índice 1: ["pomme", "kiwi", "poire", "orange", "fraise"]
fruits.extend(["cerise", "raisin"])  # Adiciona vários elementos: ["pomme", "kiwi", "poire", "orange", "fraise", "cerise", "raisin"]

# Remoção de elementos
fruits.remove("poire")  # Remove a primeira ocorrência de "poire"
fruit_supprime = fruits.pop(2)  # Remove e retorna o elemento no índice 2
del fruits[0]  # Remove o elemento no índice 0
fruits.clear()  # Esvazia a lista completamente

Operações comuns em listas

nombres = [3, 1, 4, 1, 5, 9, 2, 6]

# Tamanho
longueur = len(nombres)  # 8

# Mínimo e máximo
minimum = min(nombres)  # 1
maximum = max(nombres)  # 9

# Soma
total = sum(nombres)  # 31

# Ordenação
nombres.sort()  # Ordena a lista in-place: [1, 1, 2, 3, 4, 5, 6, 9]
nombres_decroissants = sorted(nombres, reverse=True)  # Retorna uma nova lista ordenada: [9, 6, 5, 4, 3, 2, 1, 1]

# Inversão
nombres.reverse()  # Inverte a lista in-place

# Contagem
occurrences_de_1 = nombres.count(1)  # 2

# Busca de índice
premier_index_de_1 = nombres.index(1)  # Índice da primeira ocorrência de 1

List comprehension

A list comprehension é uma sintaxe concisa para criar listas a partir de sequências existentes.

# Sem list comprehension
carres = []
for x in range(10):
    carres.append(x**2)

# Com list comprehension
carres = [x**2 for x in range(10)]  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Com condição
nombres_pairs = [x for x in range(20) if x % 2 == 0]  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# List comprehension mais complexa
matrice = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
aplati = [nombre for ligne in matrice for nombre in ligne]  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Casos de uso comuns das listas

As listas são ideais quando você precisa:

  • Armazenar uma coleção de elementos em uma ordem específica
  • Modificar a coleção com frequência (adicionar/remover elementos)
  • Acessar os elementos pela posição
  • Armazenar duplicatas

Exemplos de aplicações:

  • Lista de tarefas
  • Histórico de ações
  • Filas de processamento
  • Séries temporais de dados

Tuplas

As tuplas são semelhantes às listas, mas são imutáveis (não podem ser modificadas após a criação). Essa característica as torna mais eficientes em termos de memória e desempenho.

Criação de tuplas

# Tupla vazia
mon_tuple = ()

# Tupla com um único elemento (exige uma vírgula)
singleton = (42,)

# Tupla com vários elementos
coordonnees = (10, 20)
personne = ("Alice", 30, "Ingénieure")

# Criação sem parênteses (packing)
autre_tuple = 1, 2, 3

# Criação com a função tuple()
caracteres = tuple("Python")  # ('P', 'y', 't', 'h', 'o', 'n')

Acesso aos elementos de uma tupla

O acesso aos elementos de uma tupla funciona como nas listas:

coordonnees = (10, 20, 30, 40, 50)

x = coordonnees[0]  # 10
y = coordonnees[1]  # 20
dernier = coordonnees[-1]  # 50
sous_tuple = coordonnees[1:4]  # (20, 30, 40)

Desempacotamento de tupla (unpacking)

Uma característica particularmente útil das tuplas é o desempacotamento:

# Desempacotamento básico
point = (10, 20)
x, y = point  # x = 10, y = 20

# Desempacotamento com * para capturar vários elementos
premier, *milieu, dernier = (1, 2, 3, 4, 5)
# premier = 1, milieu = [2, 3, 4], dernier = 5

# Troca de variáveis
a, b = 1, 2
a, b = b, a  # a = 2, b = 1

Operações em tuplas

coordonnees = (10, 20, 30)
plus_dimensions = coordonnees + (40, 50)  # Concatenação: (10, 20, 30, 40, 50)
repete = coordonnees * 2  # Repetição: (10, 20, 30, 10, 20, 30)

Métodos de tupla

Como as tuplas são imutáveis, elas têm menos métodos do que as listas:

nombres = (3, 1, 4, 1, 5, 9, 2)

longueur = len(nombres)  # 7
occurrences_de_1 = nombres.count(1)  # 2
premier_index_de_1 = nombres.index(1)  # 1

Casos de uso comuns das tuplas

As tuplas são preferíveis quando:

  • Você tem uma coleção de elementos que não vai mudar
  • Você quer evitar a modificação acidental dos dados
  • Você precisa de uma chave hashable para dicionários (listas não podem ser chaves)
  • Você retorna vários valores de uma função

Exemplos de aplicações:

  • Coordenadas (x, y, z)
  • Registros de banco de dados
  • Chaves compostas
  • Valores RGB de cores
  • Parâmetros de configuração fixos

Dicionários

Os dicionários são coleções não ordenadas de pares chave-valor. Eles permitem acesso, inserção e remoção rápidos de elementos por chave.

Criação de dicionários

# Dicionário vazio
mon_dict = {}

# Dicionário com pares chave-valor
etudiant = {
    "nom": "Martin",
    "age": 22,
    "cours": ["Mathématiques", "Informatique", "Physique"]
}

# Criação com a função dict()
coordonnees = dict(x=10, y=20, z=30)

# Criação a partir de tuplas chave-valor
items = [("pomme", 3), ("banane", 5), ("orange", 2)]
inventaire = dict(items)

# Dicionário por compreensão
carre_des_nombres = {x: x**2 for x in range(6)}  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Acesso e modificação de valores

etudiant = {
    "nom": "Martin",
    "age": 22,
    "cours": ["Mathématiques", "Informatique", "Physique"]
}

# Acesso aos valores
nom = etudiant["nom"]  # "Martin"

# Modificação dos valores
etudiant["age"] = 23
etudiant["cours"].append("Chimie")

# Acesso seguro com get()
telephone = etudiant.get("telephone")  # None porque a chave não existe
telephone = etudiant.get("telephone", "Non spécifié")  # Valor padrão "Non spécifié"

# Adição de um novo par chave-valor
etudiant["email"] = "martin@example.com"

# Remoção
cours = etudiant.pop("cours")  # Remove e retorna o valor
del etudiant["age"]  # Remove o par chave-valor
etudiant.clear()  # Esvazia o dicionário

Métodos de dicionário

produits = {
    "pomme": 0.80,
    "banane": 0.50,
    "orange": 0.70
}

# Obtenção de chaves, valores e itens
cles = produits.keys()  # dict_keys(['pomme', 'banane', 'orange'])
valeurs = produits.values()  # dict_values([0.8, 0.5, 0.7])
items = produits.items()  # dict_items([('pomme', 0.8), ('banane', 0.5), ('orange', 0.7)])

# Atualização do dicionário
nouveaux_produits = {"kiwi": 1.20, "banane": 0.55}
produits.update(nouveaux_produits)  # Adiciona "kiwi" e modifica o preço de "banane"

# Verificação da existência de uma chave
if "pomme" in produits:
    print("Le prix des pommes est", produits["pomme"])

Iteração sobre dicionários

produits = {
    "pomme": 0.80,
    "banane": 0.50,
    "orange": 0.70
}

# Iteração sobre as chaves (comportamento padrão)
for produit in produits:
    print(produit)

# Iteração sobre os valores
for prix in produits.values():
    print(prix)

# Iteração sobre os pares chave-valor
for produit, prix in produits.items():
    print(f"{produit}: {prix}€")

Dicionários aninhados

# Dicionário de dicionários
etudiants = {
    "101": {
        "nom": "Alice",
        "age": 22,
        "cours": ["Math", "Informatique"]
    },
    "102": {
        "nom": "Bob",
        "age": 21,
        "cours": ["Physique", "Biologie"]
    }
}

# Acesso aos elementos aninhados
nom_etudiant_102 = etudiants["102"]["nom"]  # "Bob"
cours_alice = etudiants["101"]["cours"][1]  # "Informatique"

Casos de uso comuns dos dicionários

Os dicionários são perfeitos para:

  • Coleções em que você busca elementos por uma chave única
  • Armazenamento de dados associativos (pares chave-valor)
  • Tabelas de hash rápidas para busca
  • Representação de objetos com atributos

Exemplos de aplicações:

  • Cache de dados
  • Contagem de frequências
  • Bancos de dados em memória
  • Parâmetros de configuração
  • Armazenamento de propriedades de objetos JSON

Conjuntos

Os conjuntos (sets) são coleções não ordenadas de elementos únicos. Eles são otimizados para testar pertencimento e eliminar duplicatas.

Criação de conjuntos

# Conjunto vazio (não é possível usar {}, pois isso cria um dicionário vazio)
mon_ensemble = set()

# Conjunto com elementos
couleurs = {"rouge", "vert", "bleu"}

# Criação a partir de uma lista (elimina as duplicatas)
nombres = set([1, 2, 2, 3, 4, 4, 5])  # {1, 2, 3, 4, 5}

# Conjunto por compreensão
nombres_pairs = {x for x in range(10) if x % 2 == 0}  # {0, 2, 4, 6, 8}

Operações em conjuntos

fruits1 = {"pomme", "banane", "orange"}
fruits2 = {"orange", "kiwi", "ananas"}

# Adição e remoção de elementos
fruits1.add("fraise")
fruits1.remove("banane")  # Lança um erro se o elemento não existir
fruits1.discard("cerise")  # Não lança erro se o elemento não existir
element = fruits1.pop()  # Remove e retorna um elemento arbitrário
fruits1.clear()  # Esvazia o conjunto

# Verificação de pertencimento
"orange" in fruits2  # True
"banane" in fruits2  # False

Operações de teoria dos conjuntos

Os conjuntos permitem realizar operações matemáticas de teoria dos conjuntos:

A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}

# União (elementos que estão em A OU em B)
union = A | B  # {1, 2, 3, 4, 5, 6, 7, 8}
# ou
union = A.union(B)

# Interseção (elementos que estão em A E em B)
intersection = A & B  # {4, 5}
# ou
intersection = A.intersection(B)

# Diferença (elementos que estão em A mas NÃO em B)
difference = A - B  # {1, 2, 3}
# ou
difference = A.difference(B)

# Diferença simétrica (elementos que estão em A OU B mas NÃO em ambos)
diff_sym = A ^ B  # {1, 2, 3, 6, 7, 8}
# ou
diff_sym = A.symmetric_difference(B)

# Verificar se um conjunto é subconjunto de outro
est_sous_ensemble = {1, 2}.issubset(A)  # True

# Verificar se um conjunto é superconjunto de outro
est_sur_ensemble = A.issuperset({1, 2})  # True

Conjuntos congelados (frozenset)

Um frozenset é um conjunto imutável, o que o torna hashable. Ele pode ser usado como chave de dicionário.

# Criação de um frozenset
couleurs_primaires = frozenset(["rouge", "bleu", "jaune"])

# Uso como chave de dicionário
groupes_couleurs = {
    frozenset(["rouge", "bleu", "jaune"]): "primaires",
    frozenset(["violet", "orange", "vert"]): "secondaires"
}

Casos de uso comuns dos conjuntos

Os conjuntos são particularmente úteis para:

  • Eliminar duplicatas de uma coleção
  • Testar rapidamente o pertencimento de elementos
  • Realizar operações matemáticas com conjuntos
  • Encontrar os elementos únicos ou comuns entre coleções

Exemplos de aplicações:

  • Filtragem de duplicatas
  • Análise de dados únicos
  • Operações em conjuntos de tags
  • Gerenciamento de permissões de usuários
  • Representação de grafos (teoria dos conjuntos)

Escolhendo a estrutura de dados certa

Cada estrutura de dados tem seus pontos fortes e fracos. Veja uma tabela comparativa para ajudar você a escolher a mais adequada à sua necessidade:

EstruturaOrdenadaMutávelElementos indexadosElemento chave-valorElementos únicosCaso de uso típico
Lista✅✅✅❌❌Coleção ordenada mutável
Tupla✅❌✅❌❌Coleção ordenada imutável
Dicionário❌¹✅❌✅✅ (chaves)Mapeamento chave-valor
Conjunto❌✅❌❌✅Eliminação de duplicatas, operações de conjuntos

¹ Desde o Python 3.7, os dicionários preservam a ordem de inserção, mas não são considerados intrinsecamente ordenados em seu design.

Dicas para escolher a estrutura adequada

  • Use uma lista quando a ordem e a modificação forem importantes
  • Use uma tupla para dados somente leitura ou chaves compostas
  • Use um dicionário para buscas rápidas por chave
  • Use um conjunto quando a unicidade e as operações de conjuntos forem necessárias

Exemplo prático: análise de dados

Veja um exemplo que usa todas as estruturas de dados para analisar vendas:

# Dados de vendas (produto, quantidade, preço, categoria)
ventes = [
    ("pomme", 5, 0.80, "fruits"),
    ("banane", 3, 0.50, "fruits"),
    ("pain", 2, 1.20, "boulangerie"),
    ("lait", 1, 0.90, "laitier"),
    ("fromage", 2, 2.50, "laitier"),
    ("pomme", 2, 0.80, "fruits"),
    ("yaourt", 4, 0.60, "laitier")
]

# Uso de dicionários para agrupar por categoria
ventes_par_categorie = {}
for produit, quantite, prix, categorie in ventes:
    if categorie not in ventes_par_categorie:
        ventes_par_categorie[categorie] = []
    ventes_par_categorie[categorie].append((produit, quantite, prix))

# Uso de conjuntos para obter produtos únicos
produits_uniques = {produit for produit, _, _, _ in ventes}
print(f"Produits uniques: {produits_uniques}")  # {'pain', 'pomme', 'fromage', 'lait', 'yaourt', 'banane'}

# Uso de tuplas para armazenar os totais por categoria (imutável)
totaux_par_categorie = tuple(
    (categorie, sum(quantite * prix for _, quantite, prix in produits))
    for categorie, produits in ventes_par_categorie.items()
)
print("Totaux par catégorie:", totaux_par_categorie)

# Uso de listas e de compreensões para analisar as vendas
total_par_produit = {}
for produit, quantite, prix, _ in ventes:
    if produit in total_par_produit:
        total_par_produit[produit] = (total_par_produit[produit][0] + quantite, prix)
    else:
        total_par_produit[produit] = (quantite, prix)

# Lista ordenada dos produtos por faturamento
ca_par_produit = [(produit, quantite * prix) for produit, (quantite, prix) in total_par_produit.items()]
ca_par_produit.sort(key=lambda x: x[1], reverse=True)

print("Produits par chiffre d'affaires:")
for produit, ca in ca_par_produit:
    print(f"- {produit}: {ca:.2f}€")

Desempenho das estruturas de dados

Em aplicações que manipulam grandes quantidades de dados, o desempenho se torna importante. Veja um panorama das complexidades de tempo das operações mais comuns:

OperaçãoListaTuplaDicionárioConjunto
Acesso por índiceO(1)O(1)N/AN/A
Acesso por chaveN/AN/AO(1)¹N/A
Busca de elementoO(n)O(n)O(1)¹O(1)¹
Adição de elementoO(1)²N/AO(1)¹O(1)¹
Remoção de elementoO(n)N/AO(1)¹O(1)¹

¹ Em média. No pior caso (raro), essas operações podem ser O(n).
² A adição no final é O(1) amortizado. A inserção no meio é O(n).

Conclusão

As estruturas de dados são os blocos de construção fundamentais de qualquer programa Python. Entender suas características, vantagens e desvantagens ajudará você a escrever um código mais eficiente e mais elegante.

Para recapitular:

  • As listas são versáteis e mutáveis, perfeitas para coleções ordenadas
  • As tuplas são imutáveis e eficientes, ideais para dados somente leitura
  • Os dicionários oferecem buscas rápidas por chave, perfeitos para associações
  • Os conjuntos eliminam duplicatas e permitem operações de conjuntos eficientes

Escolher a estrutura certa para cada situação é uma habilidade que melhora com a prática. Não hesite em experimentar diferentes abordagens para resolver seus problemas com dados.

No próximo tutorial, vamos explorar as funções em Python e como usá-las para organizar e reutilizar seu código de forma eficiente.


Precisa revisar o básico de Python? Confira nosso tutorial sobre os fundamentos da sintaxe Python.

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!