【问题标题】:Lambda function for calculating sum of primes计算素数和的 Lambda 函数
【发布时间】:2020-04-26 21:47:45
【问题描述】:

在编写用于计算 2 到 n(包括两者)之间素数和的 python 程序时,我收到错误“生成器不可调用”

任何人都可以帮助解决错误或建议我在这里缺少什么吗?

n = int(input())

sum = 0
sum = sum(list(filter((lambda n: n%y != 0 for y in range(2, n)), range(2, n+1))))

print(sum)

【问题讨论】:

  • 传递给filter 的第一个参数是生成器(lambda n: n%y != 0 for y in range(2,n)),但应该是一个函数,它接受一个返回True 或False 的参数。
  • 错误命名,sum 是一个内置名称

标签: python list lambda filter primes


【解决方案1】:

您的解决方案几乎是正确的。但是您需要在 lambda 函数中使用 all,因为您希望 all n%y != 0 语句为真:

sum(list(filter((lambda n: all(n%y != 0 for y in range(2,n))), range(2,n+1))))

正如 cmets 中所指出的,您可以通过仅检查不大于数字平方根的除数来提高代码的效率:

import math
sum(list(filter((lambda n: all(n%y != 0 for y in range(2,int(math.sqrt(n))+1))), range(2,n+1))))

说明

  • n%y != 0 for y in range(2,n) 是生成器,而不是布尔值!
  • all(n%y != 0 for y in range(2,n)) 是一个布尔值,对应于n%2 != 0 and n%3 != 0 and ... and n%(n-1) != 0

【讨论】:

  • 您可以将运行内部循环的常见“技巧”仅应用于平方根,例如for y in range(2,int(math.sqrt(n))+1)
  • @tevemadar 当然,我只是尊重用户的解决方案并修复它:)
  • 您可以添加改进的。
  • @WillNess 当然。我应该添加哪一个?有很多算法,不仅仅是那些使用蛮力的......
  • 用 sqrt,不是吗?这是一个开始。
【解决方案2】:

稍微干净一点的版本:

n = int(input())
nums = range(2, n + 1)
for i in range(2, n + 1):
    nums = list(filter(lambda x: x == i or x % i, nums))

print(sum(nums))

【讨论】:

  • 不起作用,因为您在循环的每次迭代中都会覆盖 nums
  • 请输入100运行代码,你应该得到1060这是正确的答案。
  • 同意,但是用 7 运行它,你会得到 10(错误)而不是 17(正确)。
  • 遗漏了“包容性”部分,已修复。
【解决方案3】:

你也可以用列表推导这样写:

from math import sqrt, floor

sum(( p 
      for p in range(2, n+1) 
      if all( p%q != 0 for q in range(2, floor(sqrt(p))+1) ) ))

您不需要检查所有数字,只需检查自己数字的平方根之前的数字即可。

示例:您可以通过检查 10 % 2 == 0 或 10 % 5 == 0 来发现 10 = 2 * 5 不是素数。使用平方根限制,您只能检查到 3,但是这很好,因为您已经看到了 2,并将 10 定义为非素数。

如果此应用程序供您探索,您可能需要查看sieve of Eratosthenes algorithm 以查找素数,这被认为是查找小素数的最有效方法之一。

但是,如果您只需要找到素数并将它们相加,您可以随时使用像 gmpy2 这样的库。 Check this answer to know more.

【讨论】:

  • Eratosthenes 筛对于“小”(比如 12 位以下)数字是最有效的。试验师的筛子——没那么多。
【解决方案4】:

1.第一个错误:“TypeError: 'generator' object is not callable”

这个错误是因为你将一个生成器传递给filter 内置方法,你用括号“覆盖”了lambda 方法:

filter((lambda n: n%y != 0 for y in range(2,n)), range(2,n+1))

解决方案:“揭开”括号

filter(lambda n: n%y != 0 for y in range(2,n), range(2,n+1))

2。第二个错误:“SyntaxError:生成器表达式必须是 括号”:

lambda n: n%y != 0 for y in range(2,n)

错误很明显:n%y != 0 for y in range(2,n) 是一个生成器,需要用括号括起来, 在这里你想测试这个数字是否是一个素数,所以你想检查你的生成器中的所有值是否都是True

解决方案:使用内置方法all

lambda n: all(n%y != 0 for y in range(2,n))

3.最后一个错误:“TypeError: 'int' object is not callable”

sum=0

发生这种情况是因为您为变量 sum 使用了 sum 内置方法名称,因此 sum 不再是内置方法,而是一个整数

解决方案:变量的另一个名称:

n_prime_sum = 0

这是您的修复代码

n = int(input())

n_prime_sum = 0
n_prime_sum = sum(list(filter(lambda n: all(n%y != 0 for y in range(2,n)), range(2,n+1))))
n_prime_sum
# n = 10

输出:

17

另外,您可以定义一个生成所有素数 btw 2 和 n(包括两者)的函数,然后在此函数上应用 sum 内置方法:

# original code by David Eppstein, UC Irvine, 28 Feb 2002
# with comments by Eli Bendersky, https://stackoverflow.com/a/568618

def gen_primes(n):
    """Much more efficient prime generation, the Sieve of Eratosthenes"""

    D = {}

    q = 2   # The running integer that's checked for primeness

    while q <= n:
        if q not in D:
            # q is a new prime.
            # Yield it and mark its first multiple that isn't
            # already marked in previous iterations
            # 
            yield q
            D[q * q] = [q]
        else:
            # q is composite. D[q] is the list of primes that
            # divide it. Since we've reached q, we no longer
            # need it in the map, but we'll mark the next 
            # multiples of its witnesses to prepare for larger
            # numbers
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]

        q += 1

n = int(input())
n_prime_sum = sum(gen_primes(n))
print(n_prime_sum)
# n = 10

输出:

17

函数gen_prime的大部分代码来自here

【讨论】:

    【解决方案5】:

    嗯,在我的想象中,这种方法是最佳的

    • 只用(已经)已知的素数(而不是每个数字)除法
    • 直到给定数字的平方根

    import math
    
    primes=[2]
    
    def isprime(n):         # NB! this is fragile,
      s=int(math.sqrt(n))   #     relies on `primes` being
      for p in primes:      #     already fully grown
        if n%p==0:          #     up to the sqrt(n)
          return False
        if p>s:
          return True
    
    maxn=19
    for i in range(3,maxn+1):
      if isprime(i):
        primes.append(i)
    
    print(primes)
    print(sum(primes))
    

    然后是 uglification 使其成为lambda 部分

    isprime=lambda n:all(n%p!=0 for p in primes)
    

    有效,但它错过了 sqrt 魔法,然后

    isprime=lambda n:all(n%p!=0 for p in (p for p in primes if p<=int(math.sqrt(n))))
    

    它为所有已知的素数计算 int(math.sqrt(n)),但这可能是一个一次性参数,对于 filter() 或内部 lambda(后一个显示在这里):

    isprime=lambda n:all(n%p!=0 for p in (lambda s:(p for p in primes if p<=s))(int(math.sqrt(n))))
    

    我仍然不喜欢它将所有素数与 s 进行比较的事实,停在中间可能更有效,使用index(next(...)) 获取切片可以做到这一点:

    isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
    

    next()index() 两次遍历列表的一部分仍然很难看。

    然后是外循环,我将使用reduce() 来表示functools 中的那个,因为归约的累加器可能是实际的素数列表,然后它就不会是一个单独的变量。

    第 0 步将以极简的方式实现,仍然使用变量 primes,但使用元组的可怕技巧,(do,some,things,result)[3] 将做这些事情,并评估为 result

    primes=[2]
    isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
    maxn=19
    ps=functools.reduce(lambda primes,n:(primes.append(n) if isprime(n) else None,primes)[1],range(3,maxn+1),primes)
    print(ps)
    print(primes)
    print(sum(primes)) # ps and primes are the same list actually
    

    然后完成怪物:

    import math
    import functools
    
    plist=lambda maxn:functools.reduce(lambda primes,n:(primes.append(n) if (lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))]))(n) else None,primes)[1],range(3,maxn+1),[2])
    
    primes=plist(19)
    print(primes)
    print(sum(primes))
    

    测试:https://ideone.com/0y7dN9
    输出:

    [2, 3, 5, 7, 11, 13, 17, 19]
    77
    

    外卖信息是:lambdas 可能很有用,但实际上您并不总是必须使用它们。

    【讨论】:

    • 您可能应该以某种方式在打开代码中评论isprime() 的脆弱性,即如果我们在maxn=19 之后插入调用isprime(19),它会返回false(或一些其他错误,比如未指定的返回值?)。
    • @WillNess 是的,谢谢,你是对的。最初我有这个想法,但后来完全忘记了,我专注于到达单线(那个是“安全的”,因为一切都发生在“内部”)。此外,这件事仅适用于n&gt;2
    【解决方案6】:

    在阅读了所有答案并自己尝试/测试后,我重新设计了答案,您可以根据需要进行修改:

    # get the user input
    n = int(input())
    
    from functools import reduce
    
    # create a list with all the primes within the input number range
    n_prime = range(2, n + 1)
    for i in range(2, n + 1):
        n_prime = list(filter(lambda x: x == i or x % i, n_prime))
    
    # print the list of primes obtained from above
    print(n_prime)
    
    # let's add all these numbers in the above list and print the summed value
    sum_n_prime = reduce(lambda x, y : x + y, n_prime)
    print(sum_n_prime)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多