HomePage RecentChanges

Lesson14

Funcionais sobre listas

Quando utilizamos listas é comum fazer uso de vários funcionais, i.e., funções que recebem por parâmetro outras funções. Estes funcionais podem ser transformações, filtros ou acumuladores.

Nota-se que existem já um número significativo de funcionais em Python. Entre os mais comuns temos o filter, o map e o reduce, este último disponível no módulo functools. Estes podem ser utilizados sobre qualquer iterável e não apenas sobre listas.

Devemos também referir que este tipo de operadores sobre colecções são também comuns entre as novas plataformas de processamento de grandes volumes de dados. A título de exemplo, dado que também suporta Python, referimos a plataforma Apache Spark. Nota-se em particular o conjunto de transformações disponíveis, em particular em Python através do pacote pyspark.

Transformações

Uma transformação ou transformador recebe com argumentos uma lista e uma função aplicável sobre cada elemento na lista. Devolve uma lista em que cada elemento resulta da aplicação da função a cada elemento da lista original. Em geral a lista original não é modificada, sendo retornada uma nova lista.

Exemplo de implementação deste funcional:

def transforma(f, lst):
    res = []
    for x in lst:
        res = res + [f(x)]
    return res

Exemplo de utilização e paralelo com função pré-definida map:

>>> transforma(lambda x : x*x, [2, 3, 5, 7])
[4, 9, 25, 49]
>>> map(lambda x : x*x, [2, 3, 5, 7])
<map object at 0x3ae62539f60>
>>> list(map(lambda x : x*x, [2, 3, 5, 7]))
[4, 9, 25, 49]
>>> map(lambda x,y : x*x + y, [2, 3, 5, 7], [1, 2, 3, 4])
<map object at 0x3ae62542128>
>>> list(map(lambda x,y : x*x + y, [2, 3, 5, 7], [1, 2, 3, 4]))
[5, 11, 28, 53]
>>> l = [2, 3, 5, 7]
>>> transforma(lambda x : x*x, l)
[4, 9, 25, 49]
>>> l
[2, 3, 5, 7]
>>> list(map(lambda x,y : x*x + y, l, l))
[6, 12, 30, 56]
>>> l
[2, 3, 5, 7]
>>>

Neste exemplo podemos ver que a função map não retorna uma lista, mas sim um objecto que é iterável.

Filtros

Um filtro é um funcional que recebe uma lista e um predicado aplicável sobre cada elemento da lista. Devolve a lista constituída apenas pelos elementos da lista original que satisfazem o predicado, i.e., os elementos para os quais o predicado retorna True. Em geral a lista original não é modificada, sendo retornada uma nova lista.

Exemplo de implementação deste funcional:

def filtro(p, lst):
    res = []
    for x in lst:
        if p(x):
            res = res + [x]
    return res

Exemplo de utilização e paralelo com função pré-definida filter

>>> filtro(lambda x : x%2 == 0, [0, 1, 1, 2, 3, 5, 8])
[0, 2, 8]
>>> filter(lambda x : x%2 == 0, [0, 1, 1, 2, 3, 5, 8])
<filter object at 0x3ae6255c5f8>
>>> list(filter(lambda x : x%2 == 0, [0, 1, 1, 2, 3, 5, 8]))
[0, 2, 8]
>>> l = [0, 1, 1, 2, 3, 5, 8]
>>> filtro(lambda x : x%2 == 0, l)
[0, 2, 8]
>>> list(filter(lambda x : x%2 == 0, l))
[0, 2, 8]
>>> l
[0, 1, 1, 2, 3, 5, 8]
>>> 

Neste exemplo podemos ver que a função filter não retorna uma lista, mas sim um objecto que é iterável.

Acumuladores

Um acumulador recebe uma lista e um função aplicável aos elementos da lista. Aplica sucessivamente essa função aos elementos da lista e devolve o resultado da aplicação da mesma a todos os elementos. Nota-se que a função passada ao acumulador recebe em geral dois parâmetros, o resultado actual e o próximo elemento, devolvendo o valor resultante de incluir esse elemento no cálculo do resultado.

Exemplo de implementação deste funcional:

def acumulador(f, lst):
    res = lst[0]
    for x in lst[1:]:
        res = f(res, x)
    return res

Exemplo de utilização e paralelo com função reduce do módulo functools:

>>> acumulador(lambda r,x : r * x, [2, 3, 5, 7])
210
>>> from functools import reduce
>>> reduce(lambda r,x : r * x, [2, 3, 5, 7])
210
>>>

Mais exemplos

>>> conversor = lambda b: reduce(lambda x,y: x+y, list(map(lambda x, y: (ord(x) - ord('0'))*2**y, b, range(len(b)-1,-1,-1))))
>>> conversor('101')
5
>>> conversor('1')
1
>>> conversor('11110110')
246
>>>
>>> somadigitos = lambda n : reduce(lambda x,y: x+y, map(lambda x: ord(x) - ord('0'), str(n)))
>>> somadigitos(89)
17
>>> somadigitos(89192)
29
>>>
>>> somadigitos = lambda n : reduce(lambda x,y: x+y, filter(lambda x: x%2, map(lambda x: ord(x) - ord('0'), str(n))))
>>> somadigitos(89192)
19
>>>