Skip to content

Listas e dicionários

No capítulo anterior, definiu-se o conceito de coleção e mostrou-se 3 dos tipos fundamentais de coleções na linguagem Python: as listas, as strings e os dicionários.

Uma das mais poderosas técnicas associadas às coleções é a sua iteração, usando o comando for.

Neste capítulo mostra-se algumas funções que são específicas de cada coleção, começando pelas listas e dicionários.

Listas

Recordemos: em comum com as outras coleções,

  • as listas podem ser iteradas num comando for.
  • a função len() pode ser usada para determinar o numero de elementos de uma lista.
  • podemos testar se um elemento pertence a uma lista usando in.

Vejamos algumas funções que são específicas das listas.

A documentação destas funções pode ser consultada na documentação ficial da linguagem.

.append(), .insert()

a = [1, 2, 3, 4]
print(a)

a.append(10)

print('\ndepois de append(10):', a)

a.insert(1, 20)

print('\ndepois de insert(1, 20):', a)
[1, 2, 3, 4]

depois de append(10): [1, 2, 3, 4, 10]

depois de insert(1, 20): [1, 20, 2, 3, 4, 10]

.extend()

a = [1, 2, 3, 4]
print(a)

novos = [11, 12, 13, 14]
a.extend(novos)

print('\ndepois de extend([11, 12, 13, 14]):')
print(a)
[1, 2, 3, 4]

depois de extend([11, 12, 13, 14]):
[1, 2, 3, 4, 11, 12, 13, 14]

.remove(), .clear()

a = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
print(a)

a.remove(3)

print('\ndepois de remove(3):', a)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]

depois de remove(3): [1, 2, 4, 1, 2, 3, 4, 1, 2, 3, 4]

.count()

a = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
print(a)

print('\nresultado de count(1:)')
print(a.count(1))
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]

resultado de count(1:)
3

.append() como geradora de listas novas

Recordar que as listas podem ser iteradas com o comando for.

A combinação da iteração de listas com a função .append() começando numa lista vazia é uma das combinações mais poderosas para gerar novas listas.

Problema: gerar os 40 primeiros quadrados perfeitos \{i^2: i=0, 1, 2,...,39\} pondo o resultado numa lista

Podemos combinar .append() com for:

a = []
for i in range(40):
    a.append(i**2)

print(a)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521]

Problema: gerar os 40 primeiros quadrados perfeitos \{i^2: i=0, 1, 2,...,39\}, que estejam entre 400 e 800, pondo o resultado numa lista

Podemos combinar .append() com for e if:

a = []
for i in range(40):
    q = i**2
    if q >= 400 and q <= 800:
        a.append(q)

print(a)
[400, 441, 484, 529, 576, 625, 676, 729, 784]

Problema: somar os 10 primeiros números ímpares \sum\limits_{i=0}^9 2i+1

impares = []
for i in range(10):
    impares.append(2*i + 1)
print(impares)

soma = 0
for i in impares:
    soma = soma + i

print('soma dos 10 primeiros ímpares:', soma)
print('Pela soma de prog. aritm.',(1+19)/2*10)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
soma dos 10 primeiros ímpares: 100
Pela soma de prog. aritm. 100.0

Indexação

As listas têm uma numeração implícita, (a contar do zero), e podemos indexar uma lista usando lista[posição]

enzimas = ['HK', 'G6PDH', 'TPI', 'Ald', 'PFK', 'PK']
#           0       1       2      3      4      5   len()

print(enzimas[0])
print(enzimas[3])
print(enzimas[len(enzimas) -1])
HK
Ald
PK

As listas têm também uma numeração implícita com números negativos: o último elemento é -1, o penúltimo -2 e assim sucessivamente.

enzimas = ['HK', 'G6PDH', 'TPI', 'Ald', 'PFK', 'PK']
#                          -4     -3     -2     -1

print(enzimas[-4])
print(enzimas[-6])
print(enzimas[-1])
TPI
HK
PK

A indexação permite usar elementos de uma lista pela sua posição

a = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

print( 2*a[1] + a[2] + 2*a[-1] )
11

A indexação permite também modificar um elemento que está numa posição

a = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
print(a)

a[2] = 4 * 2**10 + a[-1]
print(a)
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
[1, 1, 4100, 2, 2, 2, 3, 3, 3, 4, 4, 4]

Podemos também indexar a partir da iteração de numeros inteiros

a = [1, 2, 3, 2, 1]

for e in a:
    print(e)

print('-------- dá o mesmo resultado que -----------')

for i in range(len(a)):
    print(a[i])
1
2
3
2
1
-------- dá o mesmo resultado que -----------
1
2
3
2
1

Problema: calcular as diferenças sucessivas entre os elementos de uma lista, pondo o resultado numa lista

a = [1, 1, 1, 2, 2, 2, 3, 3, 3, 5, 5, 7]

difs = []
for i in range(1, len(a)):
    d = a[i] - a[i-1]
    difs.append(d)

print(a)
print(difs)
[1, 1, 1, 2, 2, 2, 3, 3, 3, 5, 5, 7]
[0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 2]

Problema: mostrar que as diferenças sucessivas entre os quadrados perfeitos, são os números ímpares (usar os 20 primeiros)

#calcular os quadrados perfeitos
quads = []
for i in range(20):
    quads.append(i**2)

#calcular as diferenças sucessivas
difs = []
for i in range(1, len(quads)):
    d = quads[i] - quads[i-1]
    difs.append(d)

print('quadrados perfeitos', quads)
print('diferenças sucessivas', difs)
quadrados perfeitos [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]
diferenças sucessivas [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37]

A propriedade matemática anterior foi usada por Galileu no estudo da queda livre dos corpos.

As distâncias sucessivas percorridas durante a queda para a mesma unidade de tempo estão entre si como a sucessão dos números ímpares, o que implica que a distância acumulada cresce segundo o quadrado do tempo decorrido: o movimento de queda livre é uniformemente acelerado.

Listas em compreensão

O padrão

``` {.sourceCode .python} nova_lista = [] for i in uma_lista: "" nova_lista.append(p)

é tão frequente, que existe uma forma mais sucinta de gerar a nova
lista, as chamadas **listas em compreensão**.

Numa lista em compreensão constrói-se uma lista a partir de outra,
indicando a operação a efectuar a cada elemento da lista original.
Usa-se um comando `for` para percorrer a lista original.

É uma forma muito compacta de construir listas.

Como obter uma lista com numeros ímpares:

``` python
ímpares = [2*i+1 for i in range(10)]

print(ímpares)

[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

Em resumo, entre[] indica-se um "termo geral" e um comando for para percorrer a lista original

Um outro exemplo: obter os quadrados perfeitos entre 400 e 800

quads = [i**2 for i in range(30) if i**2 > 400 and i**2 < 800]

print(quads)
[441, 484, 529, 576, 625, 676, 729, 784]

Este exemplo mostra que podemos impor condições (com if) aos valores da lista numa lista em compreensão.

Num outro exemplo, pretendemos obter uma lista com as diferenças sucessivas entre quadrados perfeitos, para mostrar que são os números ímpares:

# Diferenças entre quadrados perfeitos sucessivos
# são os numeros ímpares
q = [i**2 for i in range(20)]
difs = [q[i] - q[i-1] for i in range(1, len(q))]

print('Quadrados: ', q)
print('\nDiferenças:', difs)
Quadrados:  [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

Diferenças: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37]

Problema: retirar todas as ocorrências de um elemento de uma lista

kill = 'Bad'
a = ['Good','Nice','OK','Bad','Cool','Bad','OK']
a_clean = [x for x in a if x != kill]

print(a)
print(a_clean)
['Good', 'Nice', 'OK', 'Bad', 'Cool', 'Bad', 'OK']
['Good', 'Nice', 'OK', 'Cool', 'OK']

Problema: retirar todas as ocorrências dos elemento de uma "lista negra"

black_list = ['Bad', 'So so']
a = ['Good','So so','OK','Bad','Cool','Bad','OK']
a_clean = [x for x in a if x not in black_list]

print(a)
print(a_clean)
['Good', 'So so', 'OK', 'Bad', 'Cool', 'Bad', 'OK']
['Good', 'OK', 'Cool', 'OK']

Problema: obter uma lista de numeros até 300 que sejam múltiplos de 3 e de 7

mult_3_7 = [x for x in range(301) if x%7==0 and x%3==0]

print(mult_3_7)
[0, 21, 42, 63, 84, 105, 126, 147, 168, 189, 210, 231, 252, 273, 294]

Leitura interessante:

Comprehensions in Python the Jedi way

Mais algumas funções de listas

.pop(), .reverse(), .sort()

Todas estas funções modificam uma lista, tal como .append().

a = ['seg', 'ter', 'qua', 'qui', 'sex', 'sab', 'dom']
print('lista original')
print(a)

a.reverse()
print('\nDepois de a.reverse()')
print(a)

a.sort()
print('\nDepois de a.sort()')
print(a)
lista original
['seg', 'ter', 'qua', 'qui', 'sex', 'sab', 'dom']

Depois de a.reverse()
['dom', 'sab', 'sex', 'qui', 'qua', 'ter', 'seg']

Depois de a.sort()
['dom', 'qua', 'qui', 'sab', 'seg', 'sex', 'ter']
a = ['seg', 'ter', 'qua', 'qui', 'sex', 'sab', 'dom']
print('lista original')
print(a)

a.pop()
print('Depois de a.pop()')
print(a)
x = a.pop(2)
print('\nDepois de a.pop(2)   ')
print(a)
print('O valor retirado foi', x)
lista original
['seg', 'ter', 'qua', 'qui', 'sex', 'sab', 'dom']
Depois de a.pop()
['seg', 'ter', 'qua', 'qui', 'sex', 'sab']

Depois de a.pop(2)   
['seg', 'ter', 'qui', 'sex', 'sab']
O valor retirado foi qua

Dicionários

Os dicionários são associações não ordenadas entre chaves e valores. Cada chave é única.

Indexação e iteração

A maneira de ler, inserir e modificar valores num dicionário é através das suas chaves. O operador in testa a existência de uma chave num dicionário.

d = {'H':1, 'Li':3, 'Na':11, 'K':19}

print('K: ', d['K'])
print('Li:', d['Li'])

d['O'] = 16
print('O: ', d['O'])

d['O'] = 18
print('O: ', d['O'])
K:  19
Li: 3
O:  16
O:  18
d = {'H':1, 'Li':3, 'Na':11, 'K':19}

if 'N' in d:
    print('Existe info sobre o azoto')
else:
    print('Não existe info sobre o azoto')
Não existe info sobre o azoto

A iteração percorre as chaves de um dicionário:

d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

for k in d:
    if d[k] > 10:
        print(k, '--->', d[k])
Na ---> 11
K ---> 19
O ---> 18

.update()

d = {'a': 1, 'c': 3, 'b': 2}
print(d)

e = {'p': 10, 'q': 15}
d.update(e)
print(d)
{'a': 1, 'c': 3, 'b': 2}
{'a': 1, 'c': 3, 'b': 2, 'p': 10, 'q': 15}

.clear()

d = {'a': 1, 'c': 3, 'b': 2}
print(d)

d.clear()
print(d)
{'a': 1, 'c': 3, 'b': 2}
{}

.values(),.items(), .keys()

d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

for i in d.values():
    print(i)
1
3
11
19
18
d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

for i in d.items():
    print(i)
('H', 1)
('Li', 3)
('Na', 11)
('K', 19)
('O', 18)
d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

for i in d.keys():
    print(i)
H
Li
Na
K
O

.items() é útil para simplificar um ciclo for: podemos desdobrar o par de valores e dar dois nomes diferentes:

# compare-se com o exemplo acima...
d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

for e, n in d.items():
    if n > 10:
        print (e, '--->', n)
Na ---> 11
K ---> 19
O ---> 18
# Virar um dicionário "do avesso"
d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

d2 = {}

for k in d:
    d2[d[k]] = k
print(d)
print(d2)
{'H': 1, 'Li': 3, 'Na': 11, 'K': 19, 'O': 18}
{1: 'H', 3: 'Li', 11: 'Na', 19: 'K', 18: 'O'}
# Virar um dicionário "do avesso"
d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

d2 = {}

for elem, na in d.items():
    d2[na] = elem
print(d)
print(d2)
{'H': 1, 'Li': 3, 'Na': 11, 'K': 19, 'O': 18}
{1: 'H', 3: 'Li', 11: 'Na', 19: 'K', 18: 'O'}

Problema: Contar os diferentes valores de um dicionário

a = {'Aragorn':'Humano', 'Frodo':'Hobbit',
     'Sam':'Hobbit', 'Boromir':'Humano',
     'Merry':'Hobbit', 'Took':'Hobbit',
     'Gandalf':'Feiticeiro',
     'Gimli':'Anão','Legolas':'Elfo'}

contagens = {}
for especie in a.values():
    if especie in contagens:
        contagens[especie] = contagens[especie] + 1
    else:
        contagens[especie] = 1

for e, c in contagens.items():
    print(e,c )
Humano 2
Hobbit 4
Feiticeiro 1
Anão 1
Elfo 1

Dicionários em compreensão

d = {i:i**2 for i in range(10)}
for k, v in d.items():
    print(k, '---->', v)
0 ----> 0
1 ----> 1
2 ----> 4
3 ----> 9
4 ----> 16
5 ----> 25
6 ----> 36
7 ----> 49
8 ----> 64
9 ----> 81
# Virar um dicionário "do avesso"
# usando um dicionário em compreensão
d = {'H':1, 'Li':3, 'Na':11, 'K':19, 'O':18}

d2 = {na: elem for elem, na in d.items()}

print(d)
print(d2)
{'H': 1, 'Li': 3, 'Na': 11, 'K': 19, 'O': 18}
{1: 'H', 3: 'Li', 11: 'Na', 19: 'K', 18: 'O'}

dict()

A função dict() que tenta transformar o seu argumento num dicionário. Em particular, pode aceitar pares de valores, interpretando-os como associações de chaves a valores.

pares = [('Li', 3), ('K', 19), ('O',18)]

d = dict(pares)
print(d)
{'Li': 3, 'K': 19, 'O': 18}

Função zip()

nomes = ['Enolase (S.cerevisiae)',
         'Enolase (S.pombe)',
         'Enolase (K.lactis)']
ids = ['P00924', 'P40370', 'Q70CP7']

for x in zip(ids, nomes):
    print(x)
('P00924', 'Enolase (S.cerevisiae)')
('P40370', 'Enolase (S.pombe)')
('Q70CP7', 'Enolase (K.lactis)')
nomes = ['Enolase (S.cerevisiae)',
         'Enolase (S.pombe)',
         'Enolase (K.lactis)']
ids = ['P00924', 'P40370', 'Q70CP7']

for n, i in zip(nomes, ids):
    print(i, ':', n)
P00924 : Enolase (S.cerevisiae)
P40370 : Enolase (S.pombe)
Q70CP7 : Enolase (K.lactis)
nomes = ['Enolase (S.cerevisiae)',
         'Enolase (S.pombe)',
         'Enolase (K.lactis)']
ids = ['P00924', 'P40370', 'Q70CP7']

d = {n: i for i, n in zip(nomes, ids)}

print(d)
{'P00924': 'Enolase (S.cerevisiae)', 'P40370': 'Enolase (S.pombe)', 'Q70CP7': 'Enolase (K.lactis)'}

Combinando a função zip() com a função dict(), a criação do dicionário fica ainda mais sucinta:

nomes = ['Enolase (S.cerevisiae)',
         'Enolase (S.pombe)',
         'Enolase (K.lactis)']
ids = ['P00924', 'P40370', 'Q70CP7']

d = dict(zip(nomes, ids))

print(d)
{'Enolase (S.cerevisiae)': 'P00924', 'Enolase (S.pombe)': 'P40370', 'Enolase (K.lactis)': 'Q70CP7'}