所以我从for循环中堆叠的一些过滤器中获得了一些有趣的行为。 我将从演示开始:
>>> x = range(100)
>>> x = filter(lambda n: n % 2 == 0, x)
>>> x = filter(lambda n: n % 3 == 0, x)
>>> list(x)
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]
这里我们得到预期的输出。我们在过滤器内的过滤器内有一个范围,过滤条件按我们希望的方式堆叠。现在我的问题来了。
我编写了一个函数来计算数字的相对素数。它看起来像这样:
def relative_primes(num):
'''Returns a list of relative primes, relative to the given number.'''
if num == 1:
return []
elif is_prime(num):
return list(range(1, num))
result = range(1, num)
for factor in prime_factors(num):
# Why aren't these filters stacking properly?
result = filter(lambda n: n % factor != 0, result)
return list(result)
无论出于何种原因,过滤器仅应用于从prime_factors()获取的列表中的LAST因子。例如:
>>> prime_factors(30)
[2, 3, 5]
>>> relative_primes(30)
[1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29]
我们可以看到没有从列表中删除2或3的倍数。为什么会这样?为什么上面的例子有效,但for循环中的过滤器不起作用?
答案 0 :(得分:7)
在Python 3.x中,filter()
返回生成器而不是列表。因此,仅使用factor
的最终值,因为所有三个过滤器都使用相同的factor
。您需要稍微修改lambda才能使其正常工作。
result = filter(lambda n, factor=factor: n % factor != 0, result)
答案 1 :(得分:1)
迭代器的评估是懒惰的。所有过滤器仅在语句
中进行评估return list(result)
到那时,factor
的值是最后的主要因素。 lambda
函数仅包含对本地名称factor
的引用,并将使用在执行时分配给该名称的任何值。
解决此问题的一种方法是在每次迭代中转换为列表。
作为旁注,更容易实现此功能
from fractions import gcd
def relative_primes(n):
return [i for i in range(1, n) if gcd(n, i) == 1]
修改:如果您的表现不是简单,那么您也可以试试这个:
def relative_primes(n):
sieve = [1] * n
for i in range(2, n):
if not sieve[i] or n % i:
continue
sieve[::i] = [0] * (n // i)
return list(itertools.compress(range(n), sieve))
答案 2 :(得分:1)
如果我理解正确并且如果两个整数没有共同的正因子(除数),那么两个整数是相对素数除外1.使用符号来表示最大公约数,如果gcd,则两个整数a和b是相对素数(a,b)== 1。然后您可以通过以下方式使用fractions模块。
from fractions import gcd
num = 30
relative_primes = filter(lambda x: gcd(x,num) == 1, xrange(1,num))