Estrutura de dados em Python - Pt. 1
O Python tem uma das melhores API's para manipulação de dados que eu conheço (apesar do meu pouco conhecimento em outras linguagens, um contato apenas com Ruby e PHP). Ela fornece metodos embutidos (built-in) que fazem a maior parte do trabalho sujo em manipulação de estruturas de dados.
Nessa série de posts, trarei algumas caracteristicas das estruturas mais básicas e importantes da linguagem, além de algumas técnicas de iteração nessas mesmas estruturas.
Estrutura de dados Parte 1
Listas
As duas estruturas mais utilizadas em Python são listas e tuplas. A primeira vista, elas parecem a mesma coisa, mas não se engane. Elas possuem diferenças importantes e que podem modificar todo o comportamento do seu sistema.
Listas são indexadas a partir do zero (zeroth-index), ou seja, o seu indíce inicial é 0. Listas são estruturas mutáveis e esta é uma caracteristica muito importante. Além disso, são estruturas básicas que suportam uma gama de metódos e caracteristicas. abaixo algumas delas:
lista.append(x)
O metódo append(x) adiciona um valor ('x') ao final da lista.
>>> nova_lista = [] # Inicializa uma lista vazia; >>> nova_lista.append('Carlos') # Adiciona a string 'Carlos' ao final da lista; >>> nova_lista ['Carlos']
lista.extend(L)
O extend(L) adiciona todos os itens de outra lista a lista informada.
>>> nova_lista = [1, 2, 3] # Inicializa uma lista com valores; >>> outra_lista = [4, 5, 6] # Inicializa uma nova lista com valores; >>> nova_lista.extend(outra_lista) # 'Extende' nova_lista com os valores de outra_lista; >>> nova_lista [1, 2, 3, 4, 5, 6]
Um dos truques mais legais das listas é a forma fácil com a qual você pode inverter a ordem da informação contida nela. Em algumas linguagens você precisaria fazer um loop para adicionar os valores a outra lista e etc. No Python, você pode utilizar o metódo abaixo:
ATENÇÃO: Este metódo altera o valor da lista in-place, ou seja, a lista original perde seu valor inicial. Caso deseje, faça uma cópia da lista antes de utilizar o metódo.
lista.reverse()
Inverte os valores de uma lista in-place.
>>> nova_lista = [1, 2, 3] >>> nova_lista.reverse() # Inverte a lista 'in-place' >>> nova_lista [6, 5, 4, 3, 2, 1]
lista.count(x)
Conta o numero de vezes que o valor 'x' aparece dentro da lista.
>>> nova_lista = list('ananindeua') # O metodo list() Cria uma lista a partir da string fornecida ['a', 'n', 'a', 'n', 'i', 'n', 'd', 'e', 'u', 'a'] >>> nova_lista.count('a') 3 >>> nova_lista.count('n') 3
list.sort(x)
Ordena o conteúdo da lista, in-place.
ATENÇÃO: Este metódo altera o valor da lista in-place, ou seja, a lista original perde seu valor inicial. Caso deseje, faça uma cópia da lista antes de utilizar o metódo.
>>> nova_lista = list('ananindeua') # O metodo list() Cria uma lista a partir da string fornecida ['a', 'n', 'a', 'n', 'i', 'n', 'd', 'e', 'u', 'a'] >>> nova_lista.sort() ['a', 'a', 'a', 'd', 'e', 'i', 'n', 'n', 'n', 'u']
lista.insert(i, x)
Adiciona um item 'x' no indice 'i' da lista. Lembre-se que a lista é uma estrutura que é indexada por 0, ou seja, o 0 é o primeiro valor da lista.
>>> nova_lista = 'I love Python'.split(' ') # Cria uma lista a partir de uma string, separando os valores nos espaços. ['I', 'love', 'Python'] >>> nova_lista.insert(0, 'You') ['You', 'I', 'love', 'Python']
Se você adicionar um valor maior que o último indíce da lista, o valor será adicionado ao final da lista.
lista.remove(x)
Remove o primeiro valor da lista cujo valor seja 'x'. Retorna um erro caso o valor não exista.
>>> nova_lista = 'I love Python'.split(' ') # Cria uma lista a partir de uma string, separando os valores nos espaços. ['I', 'love', 'Python'] >>> nova_lista.remove('Python') ['I', 'love'] >>> nova_lista.remove('Ruby') # Levanta um erro! ValueError: list.remove(x): x not in list # Valor 'x' não está na lista.
Você pode utilizar uma lista como uma pilha, seguindo o conceito de LIFO (Last In First Out), com os metodos append(x) (visto acima) e pop(x) abaixo.
lista.pop([i])
Remove e retorna um item de uma determinada posição, caso não seja especificado nenhum item, remove e retorna o elemento na última posição (First Out) da lista. Note que o parametro i entre colchetes quer dizer opcional, não que você deva colocar colchetes na posição.
>>> nova_lista = 'I Love Python'.split(' ') ['I', 'love', 'Python'] >>> removido = nova_lista.pop() # Remove e retorna o ultimo item; 'Python' >>> nova_lista ['I', 'Love']
List slicing (Fatiamento de listas)
Além de todos os metódos acima, as listas suportam slicing, fatiamento de listas. A construção do slicing para listas é a mesma para strings.
A sintaxe da fatia é a seguinte lista[start:end:stride] onde start é o indice inicial, end o indice final e stride é o 'pulo' de indice. start é inclusivo e end é 'exclusivo', ou seja o valor no indice final não está incluso no retorno da fatia.
Fatias retornam novas listas de valores e não alteram o valor inicial da lista.
>>> nova_lista = 'Python is a beautiful programming language'.split(' ') ['Python', 'is', 'a', 'beautiful', 'programming', 'language'] >>> nova_lista[0:2] # Retorne os valores do index 0 até o indice 2 ['Python', 'is'] # O indice 2 ('a') é exclusivo, por isso não está no retorno >>> nova_lista[3:5] # A partir do indice 3 (inclusivo) até o indice 5 (exclusivo) ['beautiful', 'programming'] >>> nova_lista[3:] # Você pode omitir o indice final para considerar: 'Toda a lista a partir do indice 3' ['beautiful', 'programming', 'language'] >>> nova_lista[::-1] # Hack importante! Você pode inverter os valores da lista passando um indice negativo no parametro 'stride'; ['language', 'programming', 'beautiful', 'a', 'is', 'Python'] >>> nova_lista[-2:] # Passar indices negativos no parametro 'start' fatia a lista de trás pra frente; ['programming', 'language']
Pelo fato do Python ter valores passados por referência, tentar copiar uma lista da maneira padrão pode causar alguns problemas:
>>> nova_lista = [1, 2, 3, 4, 5] >>> lista_copiada = nova_lista >>> lista_copiada.append(6) >>> lista_copiada [1, 2, 3, 4, 5, 6] >>> nova_lista [1, 2, 3, 4, 5, 6]
WHAT!? O que diabos aconteceu? Simples, lembra da passagem por referência ? É exatamente isso que aconteceu. As duas variaveis apontam para o mesmo caminho na memória do computador. Isso pode ser verificado facilmente com:
>>> lista_copiada is nova_lista # Você pode comparar as duas listas; True >>> id(nova_lista) # Ou pode utilizar o metodo 'id()', que retorna o endereço na memória do objeto 140252627427208 >>> id(lista_copiada) 140252627427208
Se você desejar copiar uma lista para outra, a forma mais fácil de fazer isso é com list slicing, desta forma:
>>> lista_copiada = nova_lista[:] >>> lista_copiada.append(7) [1, 2, 3, 4, 5, 6, 7] >>> nova_lista [1, 2, 3, 4, 5, 6] >>> lista_copiada is nova_lista False >>> id(lista_copiada) 140252627588552 >>> id(nova_lista) 140252627427208
Considerações finais
Como vimos aqui, as listas são estruturas poderosas e fáceis de trabalhar, mas como já dizia o falecido Uncle Ben (de Spider Man, não Uncle Bob do Clean Code): "Com grandes poderes, vêm grandes responsabilidades".
Tenha cuidado com a maleabilidade das listas em seus programas, ou você poderá ter resultados inesperados.
No próximo post, falaremos sobre as primas das listas, as Tuplas
Até mais pessoal e Keep Coding!