Ir para o conteúdo

Listas avançadas

Laço for em índices de listas

Laços for normalmente percorrem os valores em uma lista (os elementos):

for elemento in lista:
    ## elemento variável no processo

Podemos, alternativamente, percorrer os índices da lista:

for i in range(0, len(lista), 1):
    elemento = lista[i]
    ## processa o elemento ou lista[i] diretamente

range(start, stop, inc) gera uma lista de inteiros iniciando pelo valor de start, depois start + inc, depois start + 2*inc e assim por diante até um valor antes do valor de stop.
range(stop) é um código curto para range(0, stop, 1).

>>> range(3)         ## = range(0, 3, 1)
[0, 1, 2]
>>> range(2, 8, 3)
[2, 5]

Como podemos mudar elementos em uma lista?

Digamos que queremos adicionar o número 2 a todos os números em uma lista:

>>> v = [-1, 1, 10]
>>> for e in v:
...     e = e + 2
...
>>> v
[-1, 1, 10]   ## não alterado!!

Mas o e não é um elemento da lista?!?

É preciso um elemento indexado

Mudar um elemento de uma lista requer a atribuição à um elemento indexado.

Qual é o problema?

Dentro do laço, e é uma simples variável (tipo int), no primeiro passo se torna 1, depois 3, depois 12, mas a lista v é inalterada.

Solução: é necessário indexar um elemento de uma lista para mudar o seu valor:

>>> v = [-1, 1, 10]
>>> v[1] = 4    ## atribui 4 para o 2o elemento (índice 1) em v
>>> v
[-1, 4, 10]
>>>
>>> for i in range(len(v)):
...     v[i] = v[i] + 2
...
>>> v
[1, 6, 12]

Compreensão da lista

Como criar listas de maneiras compactas?

Exemplo: compute duas listas em um laço for.

n = 16
Cgraus = [];  Fgraus = []  ## listas vazias

for i in range(n):
    Cgraus.append(-5 + i*0.5)
    Fgraus.append((9.0/5)*Cgraus[i] + 32)

Python possui um construtor compacto chamado compreensão da lista, list comprehension, para a geração de listas a partir de um laço for:

Cgraus = [-5 + i*0.5 for i in range(n)]
Fgraus = [(9.0/5)*C + 32 for C in Cgraus]

Forma geral de uma compreensão da lista, list comprehension:

lista = [expressão for elemento in lista]

Sendo que a expressão envolve o elemento

Demonstração interativa da compreensão da lista

Atravessando múltiplas listas

Podemos correr um laço sobre duas listas?

Solução 1: laço sobre índices

for i in range(len(Cgraus)):
    print Cgraus[i], Fgraus[i]

Solução 2: usar o construtor zip:

for C, F in zip(Cgraus, Fgraus):
    print C, F

Exemplo com três listas:

>>> l1 = [3, 6, 1];  l2 = [1.5, 1, 0];  l3 = [9.1, 3, 2]
>>> for e1, e2, e3 in zip(l1, l2, l3):
...     print e1, e2, e3
...
3 1.5 9.1
6 1 3
1 0 2

Listas de listas

  • Uma lista pode conter qualquer objeto, inclusive outra lista.
  • Ao invés de se armazenar uma tabela com duas listas separadas, uma para cada coluna, podemos agrupar as duas listas em uma nova:
Cgraus = range(-20, 41, 5)
Fgraus = [(9.0/5)*C + 32 for C in Cgraus]

tabela1 = [Cgraus, Fgraus]  ## lista de duas listas

print tabela1[0]     ## a lista Cgraus
print tabela1[1]     ## a lista Fgraus
print tabela1[1][2]  ## o 3o elemento em Fgraus

Tabela de colunas X tabela de linhas

  • A tabela anterior table = [Cgraus,Fgraus] é uma tabela de duas colunas.
  • Vamos fazer uma tabela de linhas, onde cada linha é um par $C, F$:
tabela2 = []
for C, F in zip(Cgraus, Fgraus):
    linha = [C, F]
    tabela2.append(linha)

## mais compacto com a compreensão de lista:
tabela2 = [[C, F] for C, F in zip(Cgraus, Fgraus)]
print tabela2

[[-20, -4.0], [-15, 5.0], ......., [40, 104.0]]

Iteração sobre a lista de listas:

for C, F in tabela2:
    ## funciona com C e F de uma linha na tabela2

## ou
for linha in tabela2:
    C, F = linha
    ...

Ilustração da tabela de colunas

Tabela de Colunas

Ilustração da tabela de linhas

Tabela de Colunas

Extraindo sublistas

Podemos facilmente pegar partes de uma lista:

>>> A = [2, 3.5, 8, 10]
>>> A[2:]   ## do índice 2 ao final da lista
[8, 10]

>>> A[1:3]  ## do índice 1 até o índice anterior ao índice 3
[3.5, 8]

>>> A[:3]   ## do início até o índice anterior ao índice 3
[2, 3.5, 8]

>>> A[1:-1] ## do índice 1 até o elemento final
[3.5, 8]

>>> A[:]    ## a lista toda
[2, 3.5, 8, 10]

Nota: sublistas (fatias) são cópias da lista original!

Cópias e Visualizações

Um simples objeto pode ter diversos nomes conectados a ele, execute os códigos abaixo e preste atenção no resultado:

a = [1, 2, 3]
b = a
a
b
a is b
b[1] = 'oi!'
a

b é uma visualização de a, então se b muda, a também muda.

O conceito chave aqui é mutável x imutável:

  • Objetos mutáveis podem ser modificados;
  • Objetos imutáveis não podem mais ser modificados após serem criados.

O que esse pedaço de código faz?

for C, F in tabela2[Cgraus.index(10):Cgraus.index(35)]:
    print '%5.0f %5.1f' % (C, F)
  • É um laço for sobre uma sublista da tabela2.
  • Índices de sublistas: Cgraus.index(10), Cgraus.index(35), ou seja, os índices que correspondem aos elementos 10 e 35.

Saída:

10  50.0
15  59.0
20  68.0
25  77.0
30  86.0

Iteração sobre listas de listas de listas...

No caso de listas com muitos índices, como por exemplo: lista[i1][i1][i3]...

Laços sobre os índices da lista seriam:

for i1 in range(len(lista)):
    for i2 in range(len(lista[i1])):
        for i3 in range(len(lista[i1][i2])):
            for i4 in range(len(lista[i1][i2][i3])):
                valor = lista[i1][i2][i3][i4]
                ## trbalhando a variável valor

Laços sobre sublistas:

for sublista1 in lista:
    for sublista2 in lista1:
        for sublista3 in lista2:
            for sublista4 in lista3:
                valor = lista4
                ## trbalhando a variável valor

Iteração sobre uma lista de listas específica

Como podemos indexar o elemento de valor 5?

Funcionalidades de listas

Construção Significado
a = [] inicializa uma lista vazia
a = [1, 4.4, 'run.py'] inicializa a lista
a.append(elem) adiciona o objeto elem ao final
a + [1,3] adiciona duas listas
a.insert(i, e) insere o elemento e antes do índice i
a[3] elemento da lista na posição 3
a[-1] pega o último elemento da lista
a[1:3] corte: copia dos dados para uma sublist (aqui: índices 1, 2)
del a[3] apaga um elemento (índice 3)
a.remove(e) remove um elemento com o valor e
a.index('run.py') busca o índice correspondente ao valor do elemento
'run.py' in a testa se um valor está na lista
a.count(v) conta quantos elementos possuem o valor v
len(a) número dos elementos na lista a
min(a) o menor elemento na lista a
max(a) o maior elemento na lista a
sum(a) soma todos os elementos de a
sorted(a) retorna uma versão ordenada da lista a
reversed(a) retorna uma versão ordenada ao inverso da lista a
b[3][0][2] indexação de listas de listas
isinstance(a, list) é True se a é uma lista
type(a) is list é True se a é uma lista