Aula 17 – Listas e funções
Listas podem ser também argumentos ou parâmetros de funções.
É um caso especial de argumento. Se forem alteradas pela função, essa alteração é permanente. Ao passar uma lista como um argumento, estamos realmente passando uma referência a ela e não uma cópia dela (clone). Como listas são objetos mutáveis do Python, as alterações feitas nos elementos referenciados permanecerão.
P17.1) Função zera(a) que zera todos os elementos da lista a.
def zera(a):
for t in range(len(a)):
a[t] = 0
Veja o que é impresso pelas chamadas abaixo de zera():
x = [0, 2, 4, 6]
y = [1, 3, 5, 7, 9, 11]
z = [2]
print("x antes = ", x) zera(x)
print("x depois = ", x) print("y antes = ", y) zera(y)
print("y depois = ", y) print("z antes = ", z) zera(z)
print("z depois = ", z) x antes = [0, 2, 4, 6]
x depois = [0, 0, 0, 0]
y antes = [1, 3, 5, 7, 9, 11]
y depois = [0, 0, 0, 0, 0, 0]
z antes = [2]
z depois = [0]
P17.2) Função preenche(a, x) que substitui todos os elementos da lista a pelo elemento x.
def preenche(a, x):
for t in range(len(a)):
a[t] = x
Aula 17 – Listas e funções
Veja o que é impresso por cada uma das chamadas abaixo:
x = [0, 2, 4, 6]
y = ["azul", "amarelo", "verde", "vermelho", "rosa", "preto"]
z = [(-1, 2), (2, 1), (-2, -3)]
print("x antes = ", x) preenche(x, 0)
print("x depois = ", x) print("y antes = ", y) preenche(y, "branco") print("y depois = ", y) print("z antes = ", z) preenche(z, (-10, -10)) print("z depois = ", z) x antes = [0, 2, 4, 6]
x depois = [0, 0, 0, 0]
y antes = ['azul', 'amarelo', 'verde', 'vermelho', 'rosa', 'preto']
y depois = ['branco', 'branco', 'branco', 'branco', 'branco', 'branco']
z antes = [(-1, 2), (2, 1), (-2, -3)]
z depois = [(-10, -10), (-10, -10), (-10, -10)]
P17.3) Função troca_valor(a, x, y) que substitui todos os elementos da lista a iguais a x por y.
P17.4) Função troca_listas(a, b) que troca os valores entre as listas a e b. Se as listas não tiverem o mesmo tamanho devolve False, senão True.
def troca_listas(a, b):
if len(a) != len(b): return False for t in range(len(a)):
a[t], b[t] = b[t], a[t]
return True
Veja abaixo o que será impresso em cada uma das chamadas seguintes:
x = [0, 2, 4, 6]
y = [1, 3]
print("x antes = ", x, "y antes = ", y) if troca_listas(x, y):
print("x depois = ", x, "y depois = ", y)
else: print("Quantidades diferentes de elementos") x = [0, 2, 4, 6, 8]
y = [1, 3, 5, 7, 9]
Aula 17 – Listas e funções
print("x antes = ", x, "y antes = ", y) if troca_listas(x, y):
print("x depois = ", x, "y depois = ", y)
else: print("Quantidades diferentes de elementos") x = [0, 2, 4, 6]
y = ["azul", "amarelo", "verde", "vermelho"]
print("x antes = ", x, "y antes = ", y) if troca_listas(x, y):
print("x depois = ", x, "y depois = ", y)
else: print("Quantidades diferentes de elementos") x = ["azul", "amarelo", "verde"]
y = [(-1, 2), (2, 1), (-2, -3)]
print("x antes = ", x, "y antes = ", y) if troca_listas(x, y):
print("x depois = ", x, "y depois = ", y)
else: print("Quantidades diferentes de elementos")
x antes = [0, 2, 4, 6] y antes = [1, 3]
Quantidades diferentes de elementos
x antes = [0, 2, 4, 6, 8] y antes = [1, 3, 5, 7, 9]
x depois = [1, 3, 5, 7, 9] y depois = [0, 2, 4, 6, 8]
x antes = [0, 2, 4, 6] y antes = ['azul', 'amarelo', 'verde', 'vermelho']
x depois = ['azul', 'amarelo', 'verde', 'vermelho'] y depois = [0, 2, 4, 6]
x antes = ['azul', 'amarelo', 'verde'] y antes = [(-1, 2), (2, 1), (-2, -3)]
x depois = [(-1, 2), (2, 1), (-2, -3)] y depois = ['azul', 'amarelo', 'verde']
Observe que a solução abaixo do problema anterior não funciona:
def troca_listas(a, b):
if len(a) != len(b): return False a, b = b, a
return True
Os valores de a e b são trocados dentro da função apenas, mas as listas passadas como parâmetros na chamada da função não são trocadas.
A função pode inclusive alterar a quantidade de elementos da lista. Por exemplo, a função abaixo recebe uma lista e elimina todos os elementos iguais a zero. Ao final da função o tamanho da lista será menor caso houvesse nela algum zero.
def EliminaZeros(a):
k = 0
Aula 17 – Listas e funções
while k < len(a):
if a[k] == 0: del a[k] # não avança k else: k += 1 # avança k
Observe na solução acima que o tamanho da lista diminui a cada del a[k]. Entretanto, a comparação k < len(a) compara k sempre com o valor atual de len(a).
Diga agora porque a solução abaixo usando o comando for não funciona.
def EliminaZeros(a):
for k in range(len(a)):
if a[k] == 0: del a[k]
P17.5) Função elimina_repetidos(x) que elimina todos os elementos repetidos da lista x. Ou seja, devolve a lista sem elementos repetidos.
def elimina_repetidos(a):
k = 0 # índice inicial da lista # varre até o penúltimo
while k < len(a):
# verifica se tem repetido a frente if a[k] in a[k + 1:]:
del a[k] # elimina e não avança o índice # não tem repetido à frente - avança o índice
else: k = k + 1
Veja o que será impresso em cada uma das chamadas abaixo:
x = [0, 2, 4, 6]
print("x antes = ", x) elimina_repetidos(x) print("x depois = ", x)
x = [0, 2, 6, 2, 0, 0, 2, 6, 8, 6, 4, 8, 4, 6]
print("x antes = ", x) elimina_repetidos(x) print("x depois = ", x) x = [0, 0, 0, 0, 0, 0]
print("x antes = ", x) elimina_repetidos(x) print("x depois = ", x) x = [0]
print("x antes = ", x) elimina_repetidos(x) print("x depois = ", x) x antes = [0, 2, 4, 6]
Aula 17 – Listas e funções
x depois = [0, 2, 4, 6]
x antes = [0, 2, 6, 2, 0, 0, 2, 6, 8, 6, 4, 8, 4, 6]
x depois = [0, 2, 8, 4, 6]
x antes = [0, 0, 0, 0, 0, 0]
x depois = [0]
x antes = [0]
x depois = [0]
Da mesma forma que a função EliminaZeros anterior, a comparação k < len(a)compara sempre com o tamanho atual da lista que vai se alterando a cada del a[k]. Podemos também gerenciar explicitamente o tamanho atual da lista como abaixo:
def elimina_repetidos(a):
tam = len(a) # tamanho da lista
k = 0 # índice inicial da lista # varre até o penúltimo
while k < tam:
# verifica se tem repetido a frente if a[k] in a[k + 1:]:
del a[k] # elimina e não avança o índice tam = tam - 1 # reduz o tamanho da lista
# não tem repetido à frente - avança o índice else: k = k + 1
A função elimina_repetidos acima usa sub-listas para buscar os elementos repetidos (if a[k]
in a[k + 1:]:).
Resolva o problema acima usando outras formas de procurar e eliminar elementos repetidos. Exemplos:
1) Repetir a solução acima, varrendo a lista do fim para o início. Nessa solução a ordem dos elementos é mantida.
2) Para cada elemento a[k] (k = 0, 1, ...), procure a partir de a[k+1] todos os iguais a a[k] e os elimine.
Funções com efeitos colaterais e funções puras
As funções que apresentamos acima alteram o conteúdo das listas enviadas como argumentos. Nesse caso, dizemos que a função tem efeitos colaterais. Em princípio o objetivo de uma função deveria ser de devolver um valor e não alterar o valor dos parâmetros. Mas não deixa de ser útil uma função poder também ter algum efeito colateral sobre os parâmetros.
Uma função pura (pure function) não produz efeito colateral. Sua comunicação com a função que a chamou é somente através dos parâmetros, que não são modificados e um valor é retornado como resultado da função.
Aula 17 – Listas e funções
As duas formas são equivalentes. Recomenda-se que sempre que possível use-se uma função pura.
Acredita-se que usando funções puras, menos erros sejam propagados nos sistemas. Este estilo de programação é conhecido como estilo funcional de programação (functional programming style).
P17.6) Função conta_elementos(a, x) que devolve quantas vezes o elemento x ocorre na lista a. É exatamente o que faz a função count() que já usamos. Suponha então que a função count() não exista e construa essa função.
P17.7) Função imprime_repetidos(a) que imprime a quantidade de vezes que cada elemento ocorre na lista a. Imprimir uma saída do tipo:
Elemento 0 ocorre <x> vezes Elemento 1 ocorre <y> vezes Elemento 2 ocorre <y> vezes ...
...
Note que se um elemento ocorre k vezes irão aparecer k linhas dizendo que o elemento ocorre k vezes.
Use a função conta_elementos do exercício anterior.
P17.8) Idem, imprimindo apenas uma linha para cada elemento repetido, isto é, se o elemento aparece k vezes, imprimir a linha com a quantidade apenas na primeira vez que ele aparece. Já resolvemos esse problema anteriormente. Basta para cada elemento verificar se ele já apareceu antes. Use também a função conta_elementos acima.
P17.9) A função conta_elementos acima, conta sempre a partir do elemento 0 da lista. Faça uma pequena modificação de modo que ela conte de um índice inicial até um índice final, ou seja,
conta_elementos(a, inicio, fim).
P17.10) Repita agora o P17.8 com a nova função conta_elementos().
P17.11) Função procura_elemento(a, x), que procura elemento igual a x na lista a,
devolvendo como o índice do primeiro elemento que é igual a x ou -1 caso não encontre. É quase a mesma coisa que a função index(x) já usada anteriormente. Assim, suponha que não exista a index(x).
P17.12) Função repetidos(a) que devolve True se a lista a tem elementos repetidos e False caso contrário.
P17.13) Função compara_listas(a, b) que compara o conteúdo das listas a e b. Devolve:
len(a) se as listas são exatamente iguais. Ou seja, o comprimento das listas a e b.
k se a[k] ≠ b[k] e a[i] = b[i] para 0 ≤ i < k.
Funções podem devolver uma lista como resultado
Uma função pode devolver como resultado uma lista. Isso facilita se queremos construir funções puras.
Aula 17 – Listas e funções
A função a seguir devolve uma lista com todos os elementos da lista recebida menos os zeros.
def ListaSemZeros(a):
# Constrói uma nova lista eliminando os zeros de a sz = [] # incialmente sz é lista vazia
for k in range(len(a)):
if a[k] != 0:
sz.append(a[k]) # adiciona elemento a sz return sz
Veja a saída para as chamadas abaixo:
b = [1, 2, 3]
print("original:",b, " - sem zeros:", ListaSemZeros(b)) b = [1, 2, 0, 3, 0, 0, 5]
print("original:",b, " - sem zeros:", ListaSemZeros(b)) b = [0, 0, 0, 0, 0]
print("original:",b, " - sem zeros:", ListaSemZeros(b)) Saída:
original: [1, 2, 3] - sem zeros: [1, 2, 3]
original: [1, 2, 0, 3, 0, 0, 5] - sem zeros: [1, 2, 3, 5]
original: [0, 0, 0, 0, 0] - sem zeros: []
Considere agora uma nova versão do P17.5 acima.
P17.14 – novo P17.5) Função elimina_repetidos(x) que devolve uma lista contendo os elementos da lista x sem repetição.
def elimina_repetidos(a):
k = len(a) # comprimento da lista i = 0 # índice inicial da lista result = [] # lista contendo o resultado # varre até o último
while i < k:
# verifica se tem repetido a frente if not (a[i] in a[i+1:]):
result.append(a[i]) # não tem - acrescenta esse à lista i = i + 1 # próximo elemento
return result
Veja abaixo o que será impresso para cada uma das chamadas a seguir:
x = [0, 2, 4, 6]
print("x antes = ", x)
Aula 17 – Listas e funções
z = elimina_repetidos(x) print("resultado = ", z)
x = [0, 2, 6, 2, 0, 0, 2, 6, 8, 6, 4, 8, 4, 6]
print("x antes = ", x) z = elimina_repetidos(x) print("resultado = ", z) x = [0, 0, 0, 0, 0, 0]
print("x antes = ", x) z = elimina_repetidos(x) print("resultado = ", z) x = [0]
print("x antes = ", x) z = elimina_repetidos(x) print("resultado = ", z)
P17.15) Função primos_ate(n) que devolve uma lista com todos os primos menores que n.
Lembrando agora que basta procurar os divisores até a raiz quadrada de n, como fizemos em soluções anteriores, basta testar apenas com os primos anteriores à raiz quadrada de n e não com todos os números possíveis. Faremos isso, criando uma lista com os primos à medida que os encontrarmos.
from math import sqrt def primos_ate(n):
""" (int) -> list
Recebe um inteiro n e cria e retorna a lista dos números primos menores que n.
"""
lista_primos = []
for i in range(2, n):
# verifica se é divisivel por algum primo da lista k = len(lista_primos)
tem_div = False for j in range(k):
# verifica se precisa continuar procurando if lista_primos[j] > sqrt (i): break
if i % lista_primos[j] == 0:
tem_div = True break
# se saiu do laço sem encontrar divisor é primo if not tem_div: lista_primos.append(i)
return lista_primos
Veja o que será impresso pela chamada abaixo caso seja digitado, por exemplo, 100 como n:
n = int(input("Entre com n:"))
Aula 17 – Listas e funções
print("Lista de primos menores que ", n) print(primos_ate(n))
Entre com n:100
Lista de primos menores que 100
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Abaixo outra versão com uma pequena modificação:
from math import sqrt def primos_ate(n):
""" (int) -> list
Recebe um inteiro n e cria e retorna a lista dos números primos menores que n.
"""
lista_primos = []
for i in range(2, n):
# verifica se é divisivel por algum primo da lista tem_div = False
# j percorre lista_primos for j in lista_primos:
# verifica se precisa continuar procurando if j > sqrt (i): break
if i % j == 0:
tem_div = True break
# se saiu do laço sem encontrar divisor é primo if not tem_div: lista_primos.append(i)
return lista_primos
P17.16) Função retira_primos(list_num) que recebe uma lista de inteiros positivos e retira dela todos os primos, devolvendo o resultado numa nova lista.
P17.17) Função seq_crescente(lista_num) que recebe uma lista com valores do mesmo tipo e devolve True se a lista está em ordem crescente e False caso contrário.
P17.18) Função Fibonacci(n) que devolve uma lista com a sequência de Fibonacci dos menores que n.
def fibonacci(n): # return Fibonacci series up to n
"""Retorna lista com a série de Fibonacci dos menores que n."""
Aula 17 – Listas e funções
result = []
a, b = 0, 1 # dois primeiros elementos da sequência # gerar todos os menores que n
while a < n:
result.append(a) # acrescente esse à lista
a, b = b, a + b # próximos elementos da sequência return result
Veja o que será impresso pela chamada abaixo.
print(Fibonacci(10000)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
P17.19) Escreva uma função Freq(numeros) que recebe uma lista numeros contendo valores entre 0 e 99 inteiros. Devolve uma lista f com 10 contadores onde f[0] = quantidade de valores entre 0 e 9, f[1] = quantidade de valores entre 10 e 19, ..., f[9] = quantidade de valores entre 90 e 99.
P17.20) Idem se os valores estão entre 0 e 999. Neste caso a lista devolvida terá 100 valores: f[0] = quantidade de valores entre 0 e 9, f[1] = quantidade de valores entre 10 e 19, ..., f[99] = quantidade de valores entre 990 e 999.
Um exemplo de biblioteca de funções - Conjuntos
Um conjunto pode ser representado por uma lista de elementos, sem repetição. Vamos construir uma biblioteca de funções que manipula conjuntos. De fato, o Python já tem um tipo set, que manipula conjuntos e já possui as funções usuais da álgebra dos conjuntos. Representar um conjunto como uma lista de elementos sem repetição é outra forma. É o que propomos abaixo.
1) Função sem_repeticao(c) que devolve uma lista contendo os elementos de c sem prestição, ou seja um conjunto.
2) Função pertence(a, x) que devolve True se o elemento x pertence ao conjunto a e False se não.
3) Função uniao(a, b) que devolve uma lista c que é a união dos conjuntos a e b.
4) Função interseccao(a, b) que devolve uma lista c que é a intersecção dos conjuntos a e b.
5) Função subtracao(a, b) que devolve uma lista c que é a diferença dos conjuntos a e b (a -b).
6) Função contem(a,b) que devolve True a contém b e False se não.
7) Função contido(a, b) que devolve True a está contido em b e False se não.
Podemos agora reunir todas estas funções num módulo (arquivo .py). Um programa que precisa manipular conjuntos pode dar simplesmente um import neste módulo.
Aula 17 – Listas e funções
Abaixo a função união(a, b). As demais ficam como exercício.
# recebe 2 conjuntos (listas) a e b. Devolve lista c = a unido com b def uniao(a, b):
# inicia c com a c = a[:]
# varre b - insere b[k] em c se não estiver em a for k in range(len(b)):
if b[k] not in a: c.append(b[k]) # retorna o c = a unido com b
return c
Ou ainda, reescrevendo o trecho acima:
# varre b - insere k em c se não estiver em a for k in b:
if k not in a: c.append(k)
Mais um exemplo de biblioteca de funções – Polinômios
Uma lista A de elementos float, pode representar um polinômio, onde A[i] é o coeficiente de xi. Ou seja, o polinômio seria:
A[0]x0 + A[1]x1+ A[2]x2 + ... + A[N]xN
A lista deve ter N+1 elementos. Ou seja, o tamanho da lista, menos 1 é o grau do polinômio. Vamos propor as seguintes funções para compor o módulo:
1) Função soma_pol(a, b) que devolve lista contendo a soma dos polinômios a e b.
2) Função sub_pol(a, b) que devolve lista contendo a diferença dos polinômios a e b.
3) Função mult_pol(a, b) que devolve lista contendo o produto dos polinômios a e b.
4) Função divt_pol(a, b) que devolve lista contendo o quociente dos polinômios a e b.
5) Função deriv_pol(a) que devolve lista contendo a derivada do polinômio a.
6) Função integ_pol(a) que devolve lista contendo a integral do polinômio a 7) Função val_pol(a, x) que devolve o valor do polinômio a no ponto x.
Podemos agora reunir todas estas funções num módulo (arquivo .py). Um programa que precisa manipular conjuntos pode dar simplesmente um import neste módulo.
Abaixo a função SomaPol(a, b). As demais ficam como exercício.
Aula 17 – Listas e funções
# recebe 2 polinômios (listas) a e b. Devolve c = a + b def SomaPol(a, b):
# copia o de grau maior em c if len(a) > len(b):
c = a[:]
# soma b
for k in range(len(b)): c[k] += b[k]
else:
c = b[:]
# soma a
for k in range(len(a)): c[k] += a[k]
# Quando uma soma é feita, o grau da soma pode diminuir # se os termos de maior grau ficarem zero.
# Elimina os zeros do final da lista - menos o c[0]
for k in range(len(c) - 1):
if c[-1] == 0: del c[-1]
else: break # retorna c = a + b return c
Ou ainda, reescrevendo o trecho acima:
# Elimina os zeros do final da lista - menos o c[0]
while len(c) > 1:
if c[-1] == 0: del c[-1]
else: break
Aula 17 – Listas e funções