2

少し前に、この (本当に) 単純なプログラムに出くわしました。最初の x 素数を出力するだけです。私は尋ねるのが恥ずかしいです、それをより「pythonic」にする方法、つまり(より)読みやすくしながら凝縮する方法はありますか?スイッチング機能は問題ありません。私は読みやすさだけに興味があります。

ありがとう

from math import sqrt


def isprime(n):
  if n ==2:
    return True
  if n % 2 ==0 : # evens
    return False

  max = int(sqrt(n))+1 #only need to search up to sqrt n 
  i=3
  while i <= max: # range starts with 3 and for odd i
    if n % i == 0:
      return False
    i+=2

  return True



reqprimes = int(input('how many primes: '))
primessofar = 0
currentnumber = 2
while primessofar < reqprimes:

  result = isprime(currentnumber)

  if result:
     primessofar+=1
     print currentnumber
     #print '\n'

  currentnumber += 1
4

8 に答える 8

7

アルゴリズム自体は Python で実装されている可能性がありますが、アルゴリズムを機能的な方法で書き直すと便利なことがよくあります。完全に異なるが、より読みやすいソリューションになる可能性があります (これはさらに Pythonic です)。

def primes(upper):
    n = 2; found = []
    while n < upper:
        # If a number is not divisble through all preceding primes, it's prime
        if all(n % div != 0 for div in found):
            yield n
            found.append( n )
        n += 1

使用法:

for pr in primes(1000):
    print pr

または、Alasdair のコメントを考慮して、より効率的なバージョン:

from math import sqrt
from itertools import takewhile

def primes(upper):
    n = 2; foundPrimes = []
    while n < upper:
        sqrtN = int(sqrt(n))
        # If a number n is not divisble through all preceding primes up to sqrt(n), it's prime
        if all(n % div != 0 for div in takewhile(lambda div: div <= sqrtN, foundPrimes)):
            yield n
            foundPrimes.append(n)
        n += 1
于 2009-11-21T13:29:15.570 に答える
6

指定されたコードはあまり効率的ではありません。代替ソリューション (同様に非効率的):

>>> from math import sqrt
>>> def is_prime(n):
...     return all(n % d for d in range(2, int(sqrt(n)) + 1))
... 
>>> def primes_up_to(n):
...     return filter(is_prime, range(2, n))
... 
>>> list(primes_up_to(20))
[2, 3, 5, 7, 11, 13, 17, 19]

このコードでは、、、、、およびを使用allしています。正確にn個の素数ではなく、特定の数までの素数を出力するため、コードと完全に同一ではありません。そのために、次のことができます。rangeintmath.sqrtfilterlist

>>> from itertools import count, islice
>>> def n_primes(n):
...     return islice(filter(is_prime, count(2)), n)
... 
>>> list(n_primes(10))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

これにより、別の 2 つの関数、つまりitertools.countとが導入されitertools.isliceます。(コードの最後の部分は Python 3.x でのみ機能します。Python 2.x では、itertools.ifilter代わりに を使用しfilterます。)


   : より効率的な方法は、エラトステネスのふるいを使用することです。

于 2009-11-21T13:29:11.420 に答える
5

スタイル ガイドからのいくつかのマイナーなこと。

  • 2 つではなく、4 つのスペースを使用します。(個人的にはタブの方が好きですが、それは Pythonic の方法ではありません。)
  • 空行が少ない。
  • 一貫した空白: n ==2:=>n == 2:
  • 変数名にはアンダースコアを使用してください: currentnumber=>current_number

  • 于 2009-11-21T13:26:26.370 に答える
    2

    私は最近、関数型PythonでProject Eulerソリューションを見つけました。これには、このような素数を操作する非常に優れた例がいくつかあります。番号7はあなたの問題にかなり近いです:

    def isprime(n):
        """Return True if n is a prime number"""
        if n < 3:
            return (n == 2)
        elif n % 2 == 0:
            return False
        elif any(((n % x) == 0) for x in xrange(3, int(sqrt(n))+1, 2)):
            return False
        return True
    
    def primes(start=2):
        """Generate prime numbers from 'start'"""
        return ifilter(isprime, count(start))
    
    于 2009-11-21T14:48:10.840 に答える
    2

    まず、イテラブルから最大値を見つけるために使用される組み込み関数であるため、変数に max を割り当てないでください。また、コードのそのセクション全体は、代わりに次のように書くことができます

    for i in xrange(3, int(sqrt(n))+1, 2):
        if n%i==0: return False
    

    また、新しい変数 result を定義して isprime によって返された値をそれに入れる代わりに、直接行うことができます

    if isprime(currentnumber):
    
    于 2009-11-21T13:39:23.460 に答える
    1

    ふるいアルゴリズム (すべての素数が 100 未満) を使用して、より Pythonic にすることができます。

    def primes(n):
        sieved = set()
        for i in range(2, n):
            if not(i in sieved):
                for j in range(i + i, n, i):
                    sieved.add(j)
        return set(range(2, n)) - sieved
    
    print primes(100)
    

    非常に小さなトリックで、目標を達成できます。

    于 2009-11-21T14:13:56.323 に答える
    1

    通常、このような単純なことには while ループを使用しません。範囲オブジェクトを作成し、そこから要素を取得します。したがって、最初のループを次のように書き換えることができます。

    for i in range( 3, int( sqrt( n ) ) + 1, 2 ):
        n % i == 0 の場合:
            偽を返す
    

    また、素数をキャッシュして、新しい数をチェックするときに以前の素数のみをチェックする方がはるかに優れています。これにより、多くの時間を節約できます (そして、この方法でより大きな素数を簡単に計算できます)。すべての素数をn簡単に取得するために以前に書いたコードを次に示します。

    def primeNumbers (終了):
        素数 = []
        素数.append( 2 )
    
        for i in range( 3, end, 2 ):
            isPrime = True
    
            素数の j の場合:
                i % j == 0 の場合:
                    isPrime = False
                    壊す
    
            プライムの場合:
                primes.append( i )
    
        素数を返す
    
    print primeNumbers( 20 )
    
    于 2009-11-21T13:40:29.807 に答える
    1

    stacktrace.itの優秀な人たち (具体的には Daniele Varrazzo) から翻訳されたこのバージョンでは、バイナリ最小ヒープを利用してこの問題を解決しています。

    from heapq import heappush, heapreplace
    
    def yield_primes():
        """Endless prime number generator."""
    
        # Yield 2, so we don't have to handle the empty heap special case
        yield 2
    
        # Heap of (non-prime, prime factor) tuples.
        todel = [ (4, 2) ]
    
        n = 3
        while True:
            if todel[0][0] != n:
                # This number is not on the head of the heap: prime!
                yield n
                heappush(todel, (n*n, n))   # add to heap
    
            else:
                # Not prime: add to heap
                while todel[0][0] == n:
                    p = todel[0][1]
                    heapreplace(todel, (n+p, p))
                    # heapreplace pops the minimum value then pushes: 
                    # heap size is unchanged
    
            n += 1
    

    このコードは私のものではなく、完全には理解していません (ただし、説明はここにあります:))。この回答をコミュニティ wiki としてマークします。

    于 2009-11-21T14:24:47.407 に答える