filter---埃氏筛法

def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

def _not_divisible(n):
    return lambda x: x % n > 0

def primes():
    yield 2
    it = _odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(_not_divisible(n), it)

for n in primes():
    if n < 1000:
        print(n)
    else:
        break

学到了filter,看到这个埃氏筛法求质数的程序,觉得挺有意思的。

思路如下:

1、首先得到一个从3开始的奇数iterator it

2、从iterator it中取首个数,该数为质数,第一轮即为3

3、然后运用filter,其中筛选函数为_not_divisible(n),n=3,此时it已经去除了3,现在it为从5开始的奇数iterator

4、筛选之后得到it=filter(_not_divisible(3),it)的Iterator

5、然后继续循环,n=next(it),由于是Iterator,所以要一个,算一个,取it的第一个5放入filter(_not_divisible(3),it)筛选,返回5

6、5为质数,打印5,然后继续运用filter,其中筛选函数为_not_divisible(n),n=5,此时it已经去除了5,现在it为不包含5的Iterator,filter(_not_divisible(5),filter(_not_divisible(3),it#注这里的it为最初的奇数Iterator))

7、继续循环,n=next(it),取最初奇数Iterator的下一个元素7,首先先用3除筛选,再用5除筛选,返回7,7为质数,打印7

8、然后继续运用filter,其中筛选函数为_not_divisible(n),n=7,此时it已经去除了7,现在it为不包含7的Iterator,filter(_not_dicisible(7),filter(_not_divisible(5),filter(_not_divisible(3),it#注这里的it为最初的奇数Iterator)))

8、继续循环,n=next(it),取最初奇数Iterator的下一个元素9,首先先用3除筛选,丢弃9,再取下一个元素11,依次用3、5、7除,返回11,11为质数,打印11

...继续循环下去

这里有一个问题,为什么不能把

lambda x: x % n > 0

直接放在filter中作为筛选函数呢?

def odd_iter():
    n=1;
    while True:
        n+=2
        yield n

def choise(n):
    return lambda x: print('check if', x, 'is divisible by', n, 'result: ', not (x % n > 0)) or x % n > 0

def primes():
    yield 2
    it=odd_iter()
    k=0
    while k<100:
        n=next(it)
        yield n
        it=filter(lambda x: print('check if', x, 'is divisible by', n, 'result: ', not (x % n > 0)) or x % n > 0,it)
        k+=1
for n in primes():
    if n<1000:
        print(n)

输出结果如下:

2
3
check if 5 is divisible by 3 result:  False
5
check if 7 is divisible by 5 result:  False
check if 7 is divisible by 5 result:  False
7
check if 9 is divisible by 7 result:  False
check if 9 is divisible by 7 result:  False
check if 9 is divisible by 7 result:  False
9
check if 11 is divisible by 9 result:  False
check if 11 is divisible by 9 result:  False
check if 11 is divisible by 9 result:  False
check if 11 is divisible by 9 result:  False
11
check if 13 is divisible by 11 result:  False
check if 13 is divisible by 11 result:  False
check if 13 is divisible by 11 result:  False
check if 13 is divisible by 11 result:  False
check if 13 is divisible by 11 result:  False
13
check if 15 is divisible by 13 result:  False
check if 15 is divisible by 13 result:  False
check if 15 is divisible by 13 result:  False
check if 15 is divisible by 13 result:  False
check if 15 is divisible by 13 result:  False
check if 15 is divisible by 13 result:  False
15
check if 17 is divisible by 15 result:  False
check if 17 is divisible by 15 result:  False
check if 17 is divisible by 15 result:  False
check if 17 is divisible by 15 result:  False
check if 17 is divisible by 15 result:  False
check if 17 is divisible by 15 result:  False
check if 17 is divisible by 15 result:  False
17
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
check if 19 is divisible by 17 result:  False
19

因为使用匿名函数筛选时,n始终都是之前yield的那个值

这个程序关键点在于每个Iterator经过筛选,又需要再次筛选,但并不是一步到位筛选,因为不是列表,而是在next的时候进行计算,类似递归

 

作业如下:

回数是指从左向右读和从右向左读都是一样的数,例如12321909。请利用filter()滤掉非回数:

def is_palindrome(n):
    c=0
    i=n
    while i>=1:
        c*=10
        c+=i%10
        i=int(i/10)
        print(c)
    return c==n
output = filter(is_palindrome, range(1, 1000))
print(list(output))

回数还可以通过将回数变为字符串根据字符比较来判断,代码非常简洁  

def is_palindrome(n):
    return str(n)==str(n)[::-1]
output = filter(is_palindrome, range(1, 100))
print(list(output))

  

 

posted on 2017-05-23 20:09  vonkimi  阅读(154)  评论(0编辑  收藏  举报

导航