【问题标题】:Odd behavior of stacked filter() calls堆叠过滤器()调用的奇怪行为
【发布时间】:2011-06-07 09:10:04
【问题描述】:

所以我从 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() 获取的列表中的最后一个因子。示例:

>>> 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 循环中的过滤器却无效?

【问题讨论】:

    标签: python filter


    【解决方案1】:

    在 Python 3.x 中,filter() 返回生成器而不是列表。因此,只有factor 的最终值被使用,因为所有三个过滤器都使用相同的factor。您需要稍微修改您的 lambda 以使其正常工作。

    result = filter(lambda n, factor=factor: n % factor != 0, result)
    

    【讨论】:

    • 另一个简洁的选项是filter(factor.__rmod__, result),诚然,这会使代码的可读性稍差。
    【解决方案2】:

    迭代器的评估是惰性的。所有过滤器将仅在语句中进行评估

    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))
    

    【讨论】:

    • 这个。好的,我认为这可能与本地名称“因素”有关。非常感谢。另外,我知道使用 gcd 的解决方案更好,但我有这个解决方案实际上更快。我有几个版本的算法。
    • 一切正常。另外,我刚刚进行了一些测试,我的算法比你建议的快两倍多,即使我添加了一个额外的素数检查。
    • @fosskers:不知道你在追求表演。添加了另一个简单的实现,应该也很快。
    【解决方案3】:

    如果我理解正确并且 如果两个整数除了 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))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-28
      相关资源
      最近更新 更多