Seção 6.8–6.11 — Percorrendo listas de forma eficiente
Podemos pesquisar se um elemento está ou não em uma lista, verificando do primeiro ao último elemento se o valor procurado estiver presente. Vejamos a listagem 6.23:
A pesquisa simplesmente compara todos os elementos da lista com o valor procurado, interrompendo a repetição ao encontrar o primeiro elemento cujo valor é igual ao procurado. A variável booleana achou será utilizada para verificar se saímos da repetição por termos achado o que procurávamos ou simplesmente porque visitamos todos os elementos sem encontrar o valor procurado. Ela é marcada como True dentro do if com a condição de pesquisa, e antes do break. Assim, achou só será True se algum elemento for igual ao valor procurado.
Modifique o primeiro exemplo (Listagem 6.23) de forma a realizar a mesma tarefa, mas sem utilizar a variável achou. Dica: observe a condição de saída do while.
Modifique o exemplo para pesquisar dois valores. Em vez de apenas p, leia outro valor v que também será procurado. Na impressão, indique qual dos dois valores foi achado primeiro.
Modifique o programa do exercício 6.9 de forma a pesquisar p e v em toda a lista e informando ao usuário a posição onde p e a posição onde v foram encontrados.
Python apresenta uma estrutura de repetição especialmente projetada para percorrer listas. A instrução for funciona de forma parecida a while, mas a cada repetição utiliza um elemento diferente da lista. A cada repetição, o próximo elemento da lista é utilizado, o que se repete até o fim da lista.
Vamos escrever um programa que utilize for para imprimir todos os elementos de uma lista (Listagem 6.24):
Quando começamos a executar o for, e é igual ao primeiro elemento da lista, no caso, 8, ou seja, L[0]. Em seguida imprimimos 8, e a execução do programa volta para o for, onde passa a valer 9, ou seja, L[1]. Na próxima repetição vai valer 15, ou seja, L[2]. Se tivéssemos que fazer a mesma tarefa com while, teríamos que escrever um programa como o da Listagem 6.25:
Embora a instrução for facilite nosso trabalho, ela não substitui completamente o while. Normalmente utilizaremos for quando quisermos processar os elementos de uma lista, um a um. O while é indicado para repetições nas quais não sabemos ainda quantas vezes vamos repetir ou onde manipulamos os índices de forma não sequencial.
A instrução break também interrompe o for. Vejamos a pesquisa escrita usando for, na Listagem 6.26:
Utilizamos a instrução break para interromper a busca depois de encontrarmos o primeiro elemento. Em seguida, utilizamos um else, parecido com o da instrução if, para imprimir a mensagem informando que o elemento não foi encontrado. O else do for só será executado se todos os elementos da lista forem visitados, ou seja, se não utilizarmos a instrução break para terminar normalmente.
💡 O else do for é um recurso poderoso e exclusivo do Python. Ele é executado somente quando o laço termina normalmente (sem break), tornando a pesquisa mais legĂvel do que usar uma variável booleana auxiliar.
Modifique o programa da listagem 6.15 usando for. Explique por que nem todos os while podem ser transformados em for.
Podemos utilizar a função range para gerar listas simples. A função range não retorna uma lista propriamente dita, mas um gerador ou generator. Por enquanto, basta entender como podemos usá-la. Imagine um programa simples que imprime de 0 a 9 na tela (Listagem 6.27):
A função range gerou números de 0 a 9 porque passamos 10 como parâmetro. Ela normalmente gera valores a partir de 0, logo, ao especificarmos apenas 10, estamos apenas informando onde parar. Experimente mudar de 10 para 20. Com a mesma função range, podemos também indicar qual é o primeiro número a gerar, passando dois parâmetros: início e fim (Listagem 6.28):
Usando 5 como início e 8 como fim, vamos imprimir os números 5, 6 e 7. A notação para o fim é a mesma utilizada com fatias — o fim é um intervalo aberto e não é incluído na faixa de valores. Se acrescentarmos um terceiro parâmetro a range, teremos como saltar entre os valores gerados. Por exemplo, range(0,10,2) gera os pares entre 0 e 10. Vejamos um exemplo que gera os 10 primeiros múltiplos de 3 (Listagem 6.29):
Observe que usamos o parâmetro especial end=" ", que indica à função print para não pular de linha após a impressão. No final do programa fizemos uma chamada a print() sem qualquer parâmetro para pular a linha. Para transformar um gerador em lista, utilize a função list (Listagem 6.30):
💡 A vantagem de utilizarmos a função range é gerar listas eficientemente, como mostrado no exemplo, sem precisar escrever os 20.000 valores no programa. Experimente list(range(20000))!
Com a função enumerate podemos ampliar as funcionalidades do for facilmente. Vejamos como imprimir uma lista onde temos o índice entre colchetes e o valor a sua direita.
Primeiro, a abordagem tradicional com um contador manual (Listagem 6.31):
Veja o mesmo programa, mas utilizando a função enumerate na Listagem 6.32:
A função enumerate gera uma tupla em que o primeiro valor é o índice e o segundo é o elemento da lista sendo enumerada. Ao utilizarmos x, e em for, indicamos que o primeiro valor da tupla deve ser colocado em x, e o segundo, em e. Assim, na primeira iteração teremos a tupla (0,5), onde x=0 e e=5.
Python permite o desempacotamento de valores de uma tupla, atribuindo um elemento da tupla a cada variável em for. O que temos a cada iteração de for é equivalente a x,e = (0,5), em que o gerador enumerate retorna cada vez uma nova tupla. Os próximos valores retornados são (1,9) e (2,13), respectivamente.
💡 Experimente substituir x,e na Listagem 6.32 por z. Antes do print, faça x,e = z. Adicione mais um print para exibir também o valor de z. Você verá que z é uma tupla!