Python: Compreensão de listas


Sobre tuplas e Zips

Algumas propriedades extras sobre tuplas são listadas aqui. Além disso usamos a fução zip() para unir objetos iteráveis de modo a poderem ser percorridos simultaneamante.

# Uma tupla não precisa de parenteses
» t = 1, 2, 3, 4
» t
↳ (1, 2, 3, 4)
» type(t)
↳ tuple
# podemos usar tuplas para declarações múltiplas
» x, y = 45, 78
» print(x,y, x+y)
↳ 45 78 123
# E percorrer uma tupla (ou lista) em um loop for
» t = [('a', 0, True), ('b', 1, False), ('c', 2, True)]
» for letra, num, b in t:
»     if b: print (num, letra)
↳ 0 a
↳ 2 c

# qualquer sequência pode ser usada no construtor de tuplas
» t = tuple('palavras')
» t
↳ ('p', 'a', 'l', 'a', 'v', 'r', 'a', 's')

# uma tupla de 1 elemento deve conter (,)
» t = ('a',)
» t
↳ ('a',)

» type(t)
↳ tuple

# tuplas para 'swap' de variáveis
» a = 'both'
» b = 'ambos'
print(a,b)
↳ both ambos
» a, b = b, a
» print(a,b)
↳ ambos both

Funções retornam uma variável ou None. No entanto essa variável pode ser uma tupla, um dicionário ou outro objeto qualquer, o que tem o efeito de ter uma função retornando mais de um valor. Por exemplo, divmod(a,b) retorna uma tupla com o resultado inteira da divisão e o resto. Funções do usuário podem fazer o mesmo, inclusive retornando outra função, como veremos.

» divmod(10,3)
↳ (3, 1)

» div, resto = divmod(10,3)
» print(div)
↳ 3

» print(resto)
↳ 1

# Um exemplo de uma função que retorna uma sequência
» def min_max(seq):
»     return min(seq), max(seq)
»
» seq = (23,45,23,78,1,23,0,-34)
» min_max(seq)
↳ (-34, 78)

» seq = {23,45,23,78,1,23,0,-34}
» min_max(seq)
↳ (-34, 78)

# funções com n argumentos
» def imprima_tudo(*args):
»     print(args)

» imprima_tudo(1,2, '3', True)
↳ (1, 2, '3', True)

# sem * temos um erro
» def imprima(args):
»     print(args)
» imprima(1,2)
↳
---------------------------------------------------------------------------
TypeError: imprima() takes 1 positional argument but 2 were given

Função zip()

Uma função interna interessante e útil é zip(). Ela recebe como argumentos duas ou mais sequências e as compacta em um objeto zip que é um iterador de tuplas, onde cada tupla contem um elemento de cada sequência usada como parâmetro. Ela retorna um iterador de tuplas, onde a i-ésima tupla contém o i-ésimo elemento de cada uma das sequências ou iteráveis fornecidas em seu argumento. Se as sequências não tem o mesmo comprimento o iterador retornado tem o comprimento da menor. Se nenhum argumento for fornecido ela retorna um iterador vazio. Com um único argumento iterável, ele retorna um iterador de tuplas de um elemento.

» seq1 = 'Blade'
» seq2 = 'Runner'
» zipado = zip(seq1, seq2)
» print(zipado)
↳ <zip object at 0x7f27c9f77500>

# use a função tuple() para visualizar o objeto zip
» print(tuple(zipado))
↳ (('B', 'R'), ('l', 'u'), ('a', 'n'), ('d', 'n'), ('e', 'e'))

# usando a mesma variável já definida
» for letra1, letra2 in zipado:
»     print(letra1, letra2)
↳ B R
↳ l u
↳ a n
↳ d n
↳ e e

# um objeto zip pode ser passado como argumento na construção
# de uma lista gerando uma lista de tuplas
» s1 = [1, 2, 3]
» s2 = ['a', 'b', 'c']
» list(zip(s1, s2))
↳ [(1, 'a'), (2, 'b'), (3, 'c')]

# várias sequências podem ser fornecidas
» s1 = 'Margem'
» s2 = 'direita'
» s3 = 'do rio'
» zip123 = zip(s1, s2, s3)
» for a,b,c in zip123:
»     print(a, b, c)
↳ M d d
↳ a i o
↳ r r
↳ g e r
↳ e i i
↳ m t o

No útimo exemplo a sequência s2 tem maior comprimento que as demais. A letra final ‘a’ foi ignorada.

Suponha que desejamos analisar duas sequências e verificar se elas possuem elementos iguais em uma mesma posição. No exemplo abaixo fazemos este teste usando zip() e definindo uma função que retorna True se houver essa coincidência. Observe que a função é abandonada na ocorrência da primeira coincidência.

Pode ocorrer que precisamos saber qual é a posição desse (ou de vários elementos comuns). Para isso usamos enumerate(). Ela tem a seguinte forma:

enumerate(iteravel, inicio=0)

onde iteravel é uma sequência ou qualquer objeto iterável. Ela retorna pares iteráveis contendo o elemento e sua posição, começando em início (com default 0) e o elemento da sequência.

# função que retorna True se houver coincidência de elementos (ou False se não houver)
» def mesmo_elemento(t1, t2):
» for i, j in zip(t1, t2):
»     if i == j:
»         return True
» return False

» t1 = [1,2,3,4,5,6,7,8,9]
» t2 = [9,8,7,6,5,4,3,2,1]
» mesmo_elemento(t1,t2)
↳ True

# Para informar a posição da coincidência usamos enumerate
» for index, element in enumerate('abc'):
»     print(index, element)
↳ 0 a
↳ 1 b
↳ 2 c

» type(enumerate('abdc'))
↳ enumerate

# Repetindo o exemplo anterior, queremos descobrir se duas sequências
# possuem elementos comuns na mesma posição, e que posição é essa

» def posicao_elemento(t1, t2):
»     ''' retorna dictionary com indice e elemento onde elemento de t1 é igual ao de t2 '''
»     dict = {}
»     if len(t2) < len(t1):
»         (t1, t2) = (t2, t1)
»     for index, i in enumerate(t1):
»         if i == t2[index]:
»             dict[index] = i
»     return dict

» t2 = [1,2,3,4,5,6,7,6,9]
» t1 = [9,8,7,4,3,4,5,6,7,8,9,0,23,45]
» posicao_elemento(t1,t2)
↳ {3: 4, 7: 6}

» t1 = 'josefina'
» t2 = 'gasolina cara'
» posicao_elemento(t1,t2)
↳ {2: 's', 5: 'i', 6: 'n', 7: 'a'}

A linha if len(t2) < len(t1): (t1, t2) = (t2, t1) garante que t2 tenha o maior comprimento. Caso contrário o teste i == t2[index] poderia poderia dar erro ao tentar obter elemento inexistente de t2.

Compreensão de Listas (List Comprehensions)


Suponha que queremos uma lista com os quadrados de todos os números de 0 até 10. Podemos conseguir isso usando um laço for:

» quadrados = []
» for i in range(11):
»     quadrados.append(i**2)
»
» quadrados
↳ [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Há uma forma alternativa no Python para conseguir o mesmo resultado chamada compreensão de listas (list comprehensions).
Sua sintaxe básica é

[expressão(item) for item in lista if condição].

» quads = [i**2 for i in range(1, 11)]
» quads
↳ [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Essa forma permite que se escreva um código mais compacto, legível e eficiente (portanto de mais rápida execução).
A expressão pode ser uma função do usuário. No exemplo usamos a função já definida anteriormente para o cálculo de fatoriais:

» def fatorial(n):
»     if n <= 1: return 1
»     else: return n*fatorial(n-1)
»
# exibindo os fatoriais de ímpares de 1 a 9
» fats = [fatorial(i) for i in [1, 3, 5, 7, 9]]
» fats
↳ [1, 6, 120, 5040, 362880]

# atuando sobre strings
» palavras = ['Organização', 'Nações', 'Unidas']
» letras = [l[0] for l in palavras]
» letras
↳ ['O', 'N', 'U']

» tamanho = [len(p) for p in palavras]
» tamanho
↳ [11, 6, 6]

Uma ou mais condições pode ser incluída na lista a ser iterada.

[expressao(item) for item in lista if condição1 if condição2 ...]

No exemplo abaixo usamos i%2, que é o resto da divisão de i por 2. Se esse resto for 0 o número é par.

# ex.: lista dos números pares de 0 até 10, exclusive
# i%2 == 0 significa que o número é par
» num = [i for i in range(10) if i%2==0 ]
» print(num)
↳ [0, 2, 4, 6, 8]

# um exemplo com strings: apenas as palavras com comprimento maior que 5
» palavras = ['casa', 'aleatório', 'rudimentar', 'longo']
» [p for p in palavras if len(p) > 5 ]
↳ ['aleatório', 'rudimentar']

# Várias condições podem ser impostas simultaneamente
# São retornados os múltiplos de 2 e 3 simultaneamente, i.e. os múltiplos de 6.
» print([i for i in range(50) if i%2==0 if i%3==0])
↳ [0, 6, 12, 18, 24, 30, 36, 42, 48]

# a expressão na lista pode conter 'if else':
# a abaixo expressão retorna 'abacaxi' para números pares,
# 'laranja' para múltiplos de 3 e 'caqui' para todos os demais
» fruits = ['abacaxi' if i%2==0 else 'laranja' if i%3==0 else 'caqui' for i in range(10)]
» print(fruits)
↳ ['abacaxi', 'caqui', 'abacaxi', 'laranja', 'abacaxi', 'caqui', 'abacaxi', 'caqui', 'abacaxi', 'laranja']

# As listas podem ser aninhadas. Abaixo a lista externa percorre letras,
# a lista interna percorre números
» matriz = [[i+j for i in 'abcd'] for j in '1234']
» matriz
↳ [['a1', 'b1', 'c1', 'd1'],
   ['a2', 'b2', 'c2', 'd2'],
   ['a3', 'b3', 'c3', 'd3'],
   ['a4', 'b4', 'c4', 'd4']]

Um teste pode ser negado com o operador lógico not (que inverte o booleano). Usamos também o método string.isalpha() que retorna True se string for formado apenas de caracteres (sem dígitos ou pontuações).

# teste not in
# isalpha() retorna True se a string é composta de caracteres alfabéticos
» vogais = {'a', 'e', 'i', 'o', 'u'}
» texto = 'Aprenda todas as regras e transgrida algumas 1234.'
» letras = set(texto.lower())
» consoantes = {letra for letra in letras if letra not in vogais if letra.isalpha()}
» consoantes
↳ {'d', 'g', 'l', 'm', 'n', 'p', 'r', 's', 't'}

# na expressão seguinte um set de tuplas é gerado
{(i, j) for i in range(3, 5) for j in range(2)}
↳ {(3, 0), (3, 1), (4, 0), (4, 1)}

» print([i+j for i in 'abcd' for j in 'efgh'])
↳ ['ae', 'af', 'ag', 'ah', 'be', 'bf', 'bg', 'bh', 'ce', 'cf', 'cg', 'ch', 'de', 'df', 'dg', 'dh']

» substantivo = ['pão', 'pé', 'carro', 'bolo', 'mato']
» adjetivo = ['pequeno', 'bonito', 'bom', 'caro']
» ['%s %s' % (s, a) for s in substantivo for a in adjetivo if s[0] == a[0]]
↳ ['pão pequeno', 'pé pequeno', 'carro caro', 'bolo bonito', 'bolo bom']

# Podemos calcular o produto escalar de 2 vetores
» u = [1,3,4,5,6]
» v = [-1,0,9,-3,2]
» sum([a+b for a,b in zip(u,v)])
↳ 26

No cálculo do produto escalar zip(u,v) contém 5 pares que são somados formando uma lista de 5 elementos. A função sum(lista) soma esses 5 elementos.

Compreensão com dicionários

Compreensão de listas podem ser aplicadas a dicionários, alterando tanto suas chaves como valores. Lembrando dic.items() retorna uma tupla chave:valor do dicionário.

# uma compreensão para duplicar os valores em um dicionário
» dic1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
» duplo_dic1 = {k:v*2 for (k,v) in dic1.items()}
» duplo_dic1
↳ {'a': 2, 'b': 4, 'c': 6, 'd': 8, 'e': 10}

# altera texto nas chaves
» R_dic1 = {'R'+k : v*2 for (k,v) in dic1.items()}
» R_dic1
↳ {'Ra': 2, 'Rb': 4, 'Rc': 6, 'Rd': 8, 'Re': 10}

» s_dic = {l.upper(): l*3 for l in 'dna'}
» print (s_dic)
↳ {'D': 'ddd', 'N': 'nnn', 'A': 'aaa'}

# queremos construir um dicionário onde a chave é um
# par entre 1 e 10, inclusive, e o valor é seu quadrado.
# Obs. percorrer i = 1, ..., 5 e tomar seu dobro garante que usamos apenas os pares
» dic_2 = {}
» for i in range(1,6):
»     dic_2[i*2] = (i*2)**2
» dic_2
↳ {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}

# alternativamente, com compreensão
» dic_3 = {n:n**2 for n in range(1,11) if n%2 == 0}
» dic_3
↳ {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}

# o mesmo resultado será obtido com
» dic_4 = {2*n:(2*n)**2 for n in range(1,6)}
» dic_4
↳ {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}

# Podemos usar compreensões para filtrar elementos de um dicionário
» dic_4a = {k:v for (k,v) in dic_4.items() if v>36}
» dic_4a
↳ {8: 64, 10: 100}

» dic_4b = {k:v for (k,v) in dic_4.items() if v>16 if v<100}
» dic_4b
↳ {6: 36, 8: 64}

# duas condições podem ser usadas
» dic_4b = {k:v for (k,v) in dic_4.items() if v>16 if v<100}
» dic_4b
↳ {6: 36, 8: 64}

# duas condições, sobre chave e valor
» dic_4c = {k:v for (k,v) in dic_4.items() if v>15 if v<90}
» dic_4c
↳ {4: 16, 6: 36, 8: 64}

# o valor é (im)par para chave (im)par
» dic_par_impar = {i:('par' if i%2==0 else 'impar') for i in range(5)}
» dic_par_impar
↳ {0: 'par', 1: 'impar', 2: 'par', 3: 'impar', 4: 'par'}

Algumas vezes pode ser útil usar zip() para construir dicionários através de uma compreensão.

# Lists to represent keys and values
» keys = [101, 201, 301, 401, 501]
» values = ['inglês', 'francês', 'alemão', 'russo', 'espanhol']

# keys e values são colocados em um único iterável (um objeto zip)
» dic_5 = { k:v for (k,v) in zip(keys, values)}
» print(dic_5)
↳ {101: 'inglês', 201: 'francês', 301: 'alemão', 401: 'russo', 501: 'espanhol'}

# Claro que o iterável poderia ser dado diretamente como parâmetro do construtor
» dic_6 = dict(zip(keys, values))
» print(dic_6)
↳ {101: 'inglês', 201: 'francês', 301: 'alemão', 401: 'russo', 501: 'espanhol'}

# dicionários aninhados
» dicionario = {i: {j: i*j for j in range(1, 6)} for i in range(2, 5)}
» print(dicionario)
↳ {2: {1: 2, 2: 4, 3: 6, 4: 8, 5: 10}, 3: {1: 3, 2: 6, 3: 9, 4: 12, 5: 15}, 4: {1: 4, 2: 8, 3: 12, 4: 16, 5: 20}}

Nesse dicionário as chaves vão de 2 até 4 e seus valores são outros dicionários.

Compreensões de listas e de dicionários são formas elegantes e de fácil leitura. No entanto, se forem muito complexas elas podem tornar o código difícil de ler e de debugar (encontrar eventuais erros). Devemos nos lembrar que outras pessoas podem necessitar ler o nosso código, ou você mesmo, daqui a um tempo, quando dificilmente se lembrará do raciocínio que te levou à construção de bloco sofisticados e elegantes.

Função filter()


A função tem a forma de

filter(funcao, sequencia)

e constroi um iterador usando uma função booleana (que retorna True ou False) e uma sequência ou um iterável qualquer. Ela testa cada elemento da sequência usando a função e retorna apenas os elementos avaliados como True.

» idades = [5, 12, 17, 18, 24, 32]
» def maior(x):
»     if x < 18:
»         return False
»     else:
»         return True

» adultos = filter(maior, idades)
» for x in adultos:
»     print(x)
↳ 18
↳ 24
↳ 32

# observe que a função acima poderia ser escrita simplesmente como
» def maior(x):
»     return x ≥ 18

No próximo exemplo temos uma lista de dicionários. Cada entrada dessa lista é um dicionário contendo dados sobre um animal. O código define uma função pesquisa que recebe essa lista e procura quais de suas entradas contém algum valor com o substring busca.

» bicharada = [
»   {'nome': 'Asdrubal', 'especie': 'tubarão', 'peso': '290', 'habitat': 'oceano'},
»   {'nome': 'Ana Lee', 'especie': 'caranquejo', 'peso': '1.2', 'habitat': 'oceano'},
»   {'nome': 'Raul', 'especie': 'urso', 'peso': '180', 'habitat': 'floresta'},
»   {'nome': 'Joana', 'especie': 'raposa', 'peso': '21', 'habitat': 'floresta'},
»   {'nome': 'Omar Lee', 'especie': 'golfinho', 'peso': '120', 'habitat': 'oceano'},
»   {'nome': 'Tulio', 'especie': 'rato', 'peso': '1.4', 'habitat': 'doméstico'}
» ]

» def pesquisa(lista, busca):
»     def meu_iterador(x):
»         for v in x.values():
»             if busca in v:
»                 return True
»         return False
»     return filter(meu_iterador, lista)

» lista_filtrada = pesquisa(bicharada, 'tuba')
» for t in lista_filtrada:
»     print(t)
↳ {'nome': 'Asdrubal', 'especie': 'tubarão', 'peso': '290', 'habitat': 'oceano'}

» lista_filtrada = pesquisa(bicharada, 'Lee')
» for t in lista_filtrada:
»     print(t)
↳ {'nome': 'Ana Lee', 'especie': 'caranquejo', 'peso': '1.2', 'habitat': 'oceano'}
↳ {'nome': 'Omar Lee', 'especie': 'golfinho', 'peso': '120', 'habitat': 'oceano'}

Sugestão: altere o código acima para encontrar parte de um valor dentro de um campo especificado. Encontre o animal cujo habitat contém a substring ‘ocea’.

Iteradores (iterators)

No Python um iterador é um objeto que contém um número contável de elementos que podem ser iterados, ou seja, que podem ser acessados e lidos um de cada vez. Além dos laços for e das compreensões de listas e sequências no Python podemos utilizar iteradores para percorrer seuências. Eles pode ser construídos com a função

nome_iterador = iter(sequencia, marcador).

O parâmetro marcador é opcional e …..

O iterador tem o método _next()_ que fornece o próximo elemento. Uma exceção StopIteration é lançada no final, quando todos os elementos foram percorridos. O iterador é esgotado e, portanto, só pode ser percorrido uma vez.

Exemplos de uso estão no código abaixo. Lista são convertidas em iteradores, que são percorridos com next().
Se a iteração não é interrompida antes do fim um erro é lançado. Um erro é gerado no final e sua captura é usada para interromper o laço.

# Uma lista é convertida em um iterador
lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
it = iter(lista)
for k in range(len(lista)):
    print(next(it), end=' ')
a b c d e f g h

# queremos separar números positivos e negativos de uma lista
# o erro no final da iteração é usado para interromper o laço
» original = [1,6,-8,-3,0, -2, 9, 76, -45]
» positivos = []
» negativos = []
» t = iter(original)
» try:
»     while True:
»         x = next(t)
»         if x >= 0:
»             positivos.append(x)
»         else:
»             negativos.append(x)
» except StopIteration:
»     print('São positivos:' , positivos, '\nSão negativos:' , negativos)

↳ São positivos: [1, 6, 0, 9, 76]
↳ São negativos: [-8, -3, -2, -45]

Embora a mesma funcionalidade possa ser conseguida de formas diferentes a transformação de um objeto iterável em um iterador é bastante útil para se escrever classes e métodos definidos pelo programador, como veremos.

Funções Lambda

Funções são boas formas de escrever código de fácil reutilização. No entanto, algumas vezes precisamos de definir um operador de forma compacta e que será utilizado apenas naquele ponto do código. As funções lambda (ou funções anônimas) permitem a criação de funções (que sequer recebem um nome) mas agem da forma desejada sobre seus argumentos.

Funções lambda tem uma sintaxe concisa:

lambda <arg1, ..., argn> : < expressão >

Elas só podem conter uma única expressão, nenhuma declaração, deve ser escrita em linha única e não comportam anotações. São exemplos simples de funções lambda:

# uma função bem simples é a identidade.
# a definição usual seria
» def id(x):
»     return x

# usando função lambda
» i = lambda x: x
» i(9)
↳ 9

# a função não precisa ser associada a uma variável
» (lambda x: abs(x))(-9)
↳ 9

# outros ex. Soma e multiplicação
» x = lambda a, b : a + b
» x(5,7)
↳ 12

# múltiplos argumentos não são envoltos em parênteses
» exp = lambda x,y : x**y
» exp(2,3)
↳ 8

» mix = lambda x,y,z : (x**y)/z
» mix(3,4,5)
↳ 16.2

# qualquer tipo de objeto pode ser passado como argumento
# no exemplo uma tupla é passada
» u = (4,7)
» (lambda x: x[0]*x[1])(u)
↳ 28

# uma função lamba que age sobre strings
# .title torna o primeiro caracter maiúsculo
» nome_autor = lambda nome, sobrenome: f'Autor: {nome.title()} {sobrenome.title()}'
» nome_autor('richard','dawkins')
↳ 'Autor: Richard Dawkins'

Um exemplo de uso frequente consiste no uso de lambdas para fornecer um critério de ordenamento.
Vimos que a função sorted(sequencia, key) pode ordenar uma sequência de acordo com um critério dado em key. No caso abaixo a cada tupla é associado o produto de seus pares, e a ordenação é feita nessa métrica.

» p = [(3, 3), (4, 2), (2, 2), (5, 2), (1, 7)] 
» sorted(p, key=lambda x: x[0]*x[1])
↳ [(2, 2), (1, 7), (4, 2), (3, 3), (5, 2)]

# dados vetores no espaço, ordená-los em ordem crescente de módulo
# a função lambda calcula o quadrado do módulo
» v =[(1,5,3), (1,8,2), (7,8,9), (2,4,3), (2,2,-1)]
» sorted(v, key=lambda x: x[0]**2+x[1]**2+x[2]**2)
↳ [(2, 2, -1), (2, 4, 3), (1, 5, 3), (1, 8, 2), (7, 8, 9)]

No exemplo seguinte definimos uma função que recebe um argumento e opera nele com uma função lambda. Essa última, por sua vez, recebe outro argumento. O exemplo também ilustra o fato de que uma função é um objeto e pode ser atribuída à uma variável.

# queremos uma função que multiplica seu argumento por um número especificado
# n pode ser visto como um parâmetro
» def vezes_n(n):
»     return lambda a : a * n

» funcao_duplicar = vezes_n(2)
» funcao_triplicar = vezes_n(3)
» funcao_x1000 = vezes_n(1000)

» funcao_duplicar(23)
↳ 46

» funcao_triplicar(15)
↳ 45

» funcao_x1000(12.345)
↳ 12345.0

A minha_funcao abaixo é uma função lambda com dois argumentos sendo um deles outra função. No primeiro caso 2 + 2*10 = 22. No segundo caso 4 + (4)**3 -6 = 62.

» minha_funcao = lambda x, f: x + f(x)
» minha_funcao(2, lambda x: x*10 )
↳ 22
» minha_funcao(4, lambda x: x**3-6)
↳ 62

Função map()

Lambdas são muito usadas junto com a função map() que tem a seguinte assinatura:

map(funcao, iteravel1, ..., iteraveln).

Os dois argumentos são obrigatórios. A função percorre os iteráveis fornecidas usando a função especificada. Essa função deve usar um elemento de cada iterável. Ela usa um algoritmo otimizado para realizar sua transformação, o que a torna mais eficiente e rápida do que laços usuais do Python.

Ela retorna um objeto iterável map que pode ser convertido em lista com list(). Alguns exemplos:

# a operação abaixo concatena duas strings
» def concatena(a, b):
»     return (a + ' ' + b)
» iter1 = ('banana', 'laranja', 'uva')
» iter2 = ('nanica', 'bahia', 'syrah')
» x = map(concatena, iter1, iter2)

# para ver o resultado podemos percorrer a iterável gerada
# cada i no laço é uma única string (como 'banana nanica')
» for i in x:
»     print(i)
↳ banana nanica
↳ laranja bahia
↳ uva syrah

# a funcão pow(x,y) retorna x^y (x elevado a y)
# duas sequências devem ser dadas em map
» y = map(pow, [6,7,8],[3,2,1])
» for i in y:
»     print(i, end=' - ')
↳ 216 - 49 - 8 -

# a função pode ser uma lambda
# duplicar cada elemento da lista
» lista = [10, 25, 17, 9, 30, -5]
» lista_2 = map(lambda n : n*2, lista)
# para exibir a sequência retornada podemos transformá-la em uma lista
» list(lista_2)
↳ [20, 50, 34, 18, 60, -10]

O uso de funções lambda pode tornar mais compacto o uso de map.

# para retornar uma lista de quadrados
» def quadrado(n):
»     return n**2
» numeros = [1, 2, 3, 4, 5]
» quadrados = map(quadrado, numeros)
» list(quadrados)
↳ [1, 4, 9, 16, 25]

# o mesmo resultado pode ser conseguido usando lambdas
» list(map(lambda x:x**2, range(1,6)))
↳ [1, 4, 9, 16, 25]

# abs() é função interna, que retorna valor absoluto
» nums = [-5, -3, -1, 0, 1, 3, 5]
» absolutos = list(map(abs, nums))
» absolutos
↳ [5, 3, 1, 0, 1, 3, 5]

# somar e multiplicar com 3 listas
» list(map(lambda i, j, k: i+j*k, [2, 4], [1, 3], [7, 8]))
↳ [9, 28]

# strip() remove string dados nas extremidades da string
» traco = ['---12356.876-', '-casa-da-vó---', '-mil-', '---']
» list(map(lambda s: s.strip("-"), traco))
↳ ['12356.876', 'casa-da-vó', 'mil', '']

# função recebe um número e retorna tuplas de 3 elementos
» def pot_1_2_3(x):
»     return x, x ** 2, x ** 3
» numeros = [1, 2, 3, 4]
» list(map(pot_1_2_3, numeros))
↳ [(1, 1, 1), (2, 4, 8), (3, 9, 27), (4, 16, 64)]

# a mesma coisa usando lambda
» list(map(lambda x: (x, x**2, x**3), numeros))
↳ [(1, 1, 1), (2, 4, 8), (3, 9, 27), (4, 16, 64)]

Em muitos casos uma compreensão de lista faz o mesmo que uma iteração via map(). No entanto é útil conhecer a função não apenas para poder ler e compreender código escrito por outras pessoas mas também para eventuais situações onde ela pode ser mais simples ou mais eficaz.

🔺Início do artigo

Bibliografia

Consulte a bibliografia no final do primeiro artigo dessa série.

2 comentários sobre “Python: Compreensão de listas

    • FORTRAN é bastante usado ainda hoje e continua em desenvolvimento. Python é uma linguagem mais moderna de mais “alto nível”, no sentido em que entrega para o programador uma interface mais simples. O programador acaba escrevendo menos linhas para fazer a mesa tarefa. Acredito que é mais fácil aprender python que fortran.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *