Um pouco de funcional III

26jul10

Dando continuidade a Um pouco de Funcional, hoje o post é sobre a função filter.

Filter

Imagem do livro Python para Desenvolvedores (Creative Commons)

A função filter deve ser utilizada quando é necessário filtrar uma sequência. Sua utilização segue o seguinte modelo

filter(func,seq) #func
filter(None,seq) #None

Em alguns casos também pode ser reproduzido com list comprehension dessa maneira

[item for item in seq if func(seq)] #func
[item for item in seq if item]      #None

A função filter retorna uma sequência formada por todos os itens em que func(item) é True. Quando é usada com None, retorna os itens que são True.

>>> def func(item):
 return item%15==0 and not item%10==0

>>> filter(func,range(100))
[15, 45, 75]
>>> [item for item in range(100) if func(item)]
[15, 45, 75]

>>> filter(None,[1,0,None,False,True,"Filter",""])
[1, True, 'Filter']
>>> [item for item in [1,0,None,False,True,"Filter",""] if item]
[1, True, 'Filter']

Em Python 2.x o retorno de filter sempre é uma lista, exceto quando a sequência é uma String ou Tupla, nesse caso o retorno é do tipo da sequência.

>>> filter(lambda x: not x%2,range(5))
[0, 2, 4]
>>> filter(lambda x: not x%2,tuple(range(5))) # tupla retorna tupla
(0, 2, 4)

Em Python 3 o retorno de filter é um iterator.

>>> filter(lambda x: len(x)>5,["Django","Web2py","CherryPy","GAE"])
<filter object at 0xb7b8a70c>
>>> from itertools import ifilterfalse
>>> list(ifilterfalse(None,[1,0,None,False,True,"Filter",""]))
[0, None, False, '']

ifilterfalse é uma função do módulo itertools que assemelha-se a filter porém retorna um iterator com todos os itens em que  func(item) é False.

Abaixo segue algumas utilizações de filter

Filtrar as pastas do diretório

>>> filter(os.path.isdir,os.listdir(r'/home/rodrigoclira/'))

Filtrar os palíndromos de uma lista de strings

>>> filter(lambda x: x[::-1]==x,["casa","ovo","palavra","radar"])
['ovo', 'radar']

O número 3.025 possui a seguinte característica: 30 + 25 = 55 e 55^2 = 3025. Escreva um  programa que mostre todos os números com quatro algarismos que possuem a  citada característica

>>> filter(lambda x : (x/100 + x%100)**2==x,range(1000,10000))
[2025, 3025, 9801]

Encontrar a soma de todos números amigos menores que 10000.

>>> divisores = lambda num: sum(filter(lambda y: num%y==0,range(1,(num/2)+1,[1,2][num%2])))
>>> sum(map(lambda (div,num): num ,filter(lambda (div,num): div!=num and divisores(div)==num ,map(lambda x: (divisores(x),x),range(1,10000)))))
31626

Explicando os passos usados para resolver o problema

1. Cria-se função que retornará a soma dos divisores de um número.

>>> num = 10
>>> filter(lambda y: num%y==0,range(1,(num/2)+1,[1,2][num%2]))
[1, 2, 5]
>>> sum(filter(lambda y: num%y==0,range(1,(num/2)+1,[1,2][num%2])))
8
>>> divisores = lambda num: sum(filter(lambda y: num%y==0,range(1,(num/2)+1,[1,2][num%2])))

2. Aplicar um mapeamento para criar uma lista de tuplas no seguinte formato

(soma_divisores,num)

>>> map(lambda x: (divisores(x),x),range(1,10000))
[(0, 1), (1, 2), (1, 3), (3, 4),...

Se você está testando cada passo desses, nessa etapa será criada uma lista com 9999 tuplas . 😉

3. As seguintes condições tem que ser verdadeiras para X ser considerado um número amigo de Y

Y = divisores(X)
X != Y e divisores(Y) == X

Então vamos filtrar a lista para obter apenas os amigos usando a ideia anterior

>>> filter(lambda (div,num): div!=num and divisores(div)==num ,map(lambda x: (divisores(x),x),range(1,10000)))
[(284, 220), (220, 284), (1210, 1184), (1184, 1210), (2924, 2620), (2620, 2924), (5564, 5020), (5020, 5564), (6368, 6232), (6232, 6368)]

4. Para finalizar é necessário somar os números amigos, que nessa abordagem é representado pela segunda posição da tupla.

>>> map(lambda (div,num): num ,filter(lambda (div,num): div!=num and divisores(div)==num ,map(lambda x: (divisores(x),x),range(1,10000))))
[220, 284, 1184, 1210, 2620, 2924, 5020, 5564, 6232, 6368]

>>> sum(map(lambda (div,num): num ,filter(lambda (div,num): div!=num and divisores(div)==num ,map(lambda x: (divisores(x),x),range(1,10000)))))
31626

Esse problema foi retirado do Project Euler, mas especificamente o problema 21. O resultado está certo, porém espero que alguém possa aconselhar uma solução mais eficiente.

Links

http://docs.python.org/library/functions.html#filter
http://aprenda-python.blogspot.com/2009/10/filter-ou-list-comprehension.html
http://www.faqs.org/docs/diveintopython/regression_filter.html
http://www.python.org.br/wiki/PythonFuncional#Filter

Anúncios


One Response to “Um pouco de funcional III”


  1. 1 Resumo VI Encontro do PUG-PE « PUG-PE

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s


%d blogueiros gostam disto: