1

As estruturas de dados do Python que você não conhece

As estruturas de dados do Python que você não conhece

As coleções mais conhecidos do Python são, sem dúvidas, os tipos dict, list, set e tuple. Juntos formam as principais estruturas utilizadas para armazenamento em memória de coleções de dados. Estes são tipos de dados nativos de propósito genérico da linguagem Python. No entanto, a biblioteca padrão da linguagem também oferece coleções alternativas com vantagens em cenários específicos.

Nessa publicação apresentarei tipos alternativos as coleções padrões do Python, elas são muito úteis em casos gerais, porém há cenários onde é possível obter ganhos de performance e armazenamento utilizando algoritmos específicos para solução de problemas mais individuais. Os tipos apresentados abaixo todos estão disponíveis na biblioteca padrão do Python. É possível utilizá-los sem nenhum esforço de instalação ou configuração.

array

Apesar do tipo de dados array ser bastante conhecido, ele é pouco usado no Python, isso porque as listas cumprem o papel de tipo sequência de uso geral da linguagem. No entanto, o tipo array possui menor custo de armazenamento, pois ele restringe os possíveis tipos armazenados na coleção. Em geral esse tipo de dado permite armazenamento de caracteres unicode, bytes, inteiros e decimais. O tipo de dado deve ser especificado no momento de criação do array e todos os elementos devem seguir o mesmo tipo.

Na inicialização do array deve-se especificar o tipo de dado que se deseja armazenar através do código de tipos, alguns códigos são: 'b' para caracteres, 'u' para caracteres unicode, 'i' para inteiro e 'l' para inteiro longo. Abaixo é dado exemplos de inicialização com operações de indexação:

from array import array
ints = array('i', [1, 2, 3, 4, 5]) # Inicializa array de inteiros com sinal
double = array('d') # Inicializa array vazio para armazenamento de números decimais com dobro de espaço
chars = array('u', 'Hello World') # Inicializa array de caracteres. Cada caracter da string será um item do array

print(ints[0]) # Imprime: 1
print(double.typecode) # Imprime: 'd'
print(chars[0:5]) # Imprime: 'Hello'
print(len(ints) * ints.itemsize) # Imprime a quantidade de bytes utilizada para armazenar a lista

namedtuple

A tupla nomeada é uma subaclasse do tipo embutido do python, a tupla, portanto, pode ser usada como uma tupla ordinária, a diferença é que a tupla nomeada atribui um nome para cada item, de forma que o acesso por indice natural e por nome são permitidos. Dessa forma, é possível representar uma sequência de dados imutáveis com melhor legibilidade.

Para utilizar essa tupla é necessário chamar a função namedtuple, que é uma fábrica de construção de classes que especificam uma determinada tupla nomeada. No exemplo abaixo é criada uma classe chamada User, em seguida é criada uma instância do usuário do tabnews e realizado operações básicas.

from collections import namedtuple

# Definição de uma nova classe
User = namedtuple('User', ['username', 'first_name', 'last_name', 'email', 'active', 'tabcash'])

# Instância de uma nova tupla nomeada
raul = User('raulpy271', 'Raul', 'Martins', 'raul@gmail.com', active=True, tabcash=100)

# Define nome completo através do nome dos campos
fullname = raul.first_name + ' ' + raul.last_name

# Imprime a quantidade de tabcash caso o usuário esteja ativo. Acessa os campos através de indíces
if raul[4]:
  print(f'{fullname} possui {raul[5]} tabcash')
else:
  print(f'{fullname} está inativo. Contate-o pelo email: {raul[3]}.')

deque

A coleção deque é chamada de fila dupla devido a sua estrutura armazenar ambos início e fim da fila, dessa forma é possível utilizá-la como uma fila ou pilha genérica. O uso dessa estrutura tem vantagens sobre um array ou lista pois operações que alteram o tamanho da coleção são feitas de forma imediata, enquanto as mesmas operações em uma lista oferecem um custo muito maior.

Abaixo é utilizada essa coleção para realizar operações em uma fila que segue o princípio FIFO - o primeiro a chegar é o primeiro a sair:

from collections import deque
fila = deque()

# Adiciona itens no final da fila
fila.append('raul')
fila.append('maria')
fila.append('joana')

# Remove itens do inicio fila
print(fila.popleft()) # Imprime 'raul'
print(fila.popleft()) # Imprime 'maria'

No exemplo anterior, para que a fila se comporte como uma pilha ao invés de remover itens do início pode-se utilizar o método pop que remove do fim da coleção, seguindo o princípio LIFO - o último a entrar é o primeiro a sair.

heapq

O módulo do python heapq oferece uma implementação para o algoritmo de fila de prioridades com heap. Nessa fila de prioridades os elementos são dispostos em uma árvore binária onde suas respectivas posições dependem da sua prioridade, na estrutura ao inserir um elemento o algoritmo decide sua posição na árvore de forma que a remoção sempre ocorra para o elemento de menor prioridade.

O módulo heapq além de oferecer uma fila de prioridades otimizada também permite realizar ordenação dos elementos utilizando o algoritmo heapsort. No exemplo abaixo é apresentado operações na fila, é possível perceber que o algoritmo utiliza uma lista ordinária para armazenar os elementos da árvore, os itens da coleção são tuplas onde o primeiro elemento corresponde a prioridade do dado armazenado:

from heapq import heappush, heappop

heap = []

heappush(heap, (3, 'marcos')); heappush(heap, (7, 'joaquina'));
heappush(heap, (0, 'vanessa')); heappush(heap, (10, 'raul'));

print(heappop(heap)) # Imprime: (0, 'vanessa')
print(heappop(heap)) # Imprime: (3, 'marcos')

heappush(heap, (1, 'josé'))

# Imprime todos os elementos de forma ordenada: josé, joaquina, raul,
while heap:
  print(heappop(heap)[1], end=', ')

Referências

Carregando publicação patrocinada...