2010-12-02 8 views
1

Ich versuche, eine Liste von Primzahlen mit der this Methode zu generieren. Ich muss jede Zahl 2 ... n durchschleifen und auf Vielfache von 2 ... n prüfen. Aus irgendeinem Grund scheint die falsche Liste geändert zu werden.Python falsche Liste ändern?

import sys 
import argparse 
import math 

parser = argparse.ArgumentParser(description='find the largest prime factor of a number') 
parser.add_argument('n', type=int, help='number') 
args = parser.parse_args() 

sieve = [] 
for i in range(2,args.n+1): sieve.append(i) # tried int(i) 


copy1 = sieve # tried making extra copies. . . 
copy2 = sieve 
copy3 = sieve 
#print int(math.sqrt(args.n)) 

for index, i in enumerate(copy1): 
    #print index, i 
    for ii in copy2: 
     #print ii 
     if i % ii == 0: 
      sieve[index]= None 


print sieve 

bekomme ich folgende Fehlermeldung:

Traceback (most recent call last): 
    File "3.py", line 22, in <module> 
    if i % ii == 0: TypeError: unsupported operand type(s) for %: 
'int' and 'str' 

Antwort

7

Sie sind nicht Kopien. Sie verwenden Referenzen, so beziehen sich copy1, copy2 und copy3 alle auf die gleiche Liste - sieve. Wenn Sie kopieren möchten, verwenden Sie:

copy1 = sieve[:] 

, die eine Kopie von sieve schaffen und ordnen Sie es copy1.

+4

Diese Verwirrung ist so üblich ... alle Material auf der Sprache (und auf allen Sprachen mit ähnlicher Semantik, BTW) sollte eine riesige rote Box mit einer Zusammenfassung davon enthalten. – delnan

+2

delnan: Außerdem wird beschrieben, wie Fließkommaarithmetik funktioniert. :-) – Ken

+0

Und in Java String == String ist nicht das, was Sie tun möchten. – Falmarri

2

Sie müssen verwenden

copy1 = sieve[:] # tried making extra copies. . . 
copy2 = sieve[:] 
copy3 = sieve[:] 

, um tatsächlich die Liste zu kopieren. Ansonsten kopieren Sie einfach den Verweis auf die Liste.

>>> a = [1,2] 
>>> b = a 
>>> c = a[:] 
>>> b[0] = 0 
>>> c[0] = 3 
>>> a 
[0, 2] 
>>> b 
[0, 2] 
>>> c 
[3, 2] 
2
copy1 = sieve 
copy2 = sieve 
copy3 = sieve 

Dies sind keine Kopien sie Verweis der sind.

primes = [2,3,5,7] 

def is_prime(n): 
    if n in primes: 
     return True 
    for item in primes: 
     if n % item == 0: 
      return False 
    return True 

assert is_prime(4) == False 
assert is_prime(29) == True 
assert is_prime(65) == False 

ist ein gutes Sieb Methode

Mehr Unit-Tests, weil sein Spaß

true_primes = [int(item) for item in '11,13,17,19,23,29,31,37,41,43,47'.split(',')] 
for item in xrange(10, 50): 
    if is_prime(item) == True: 
     assert item in true_primes 
    else: 
     assert item not in true_primes 
1

ich das nicht testen konnte, weil ich 3.2 keine Kopie von Python (argparse ist neu in Python 3.2), aber zwei offensichtliche Dinge in den Sinn kommen:

Zuerst müssen Sie tun sieve.append(int(i)).

Zweitens, Sie machen keine Kopie von Sieb, Sie erstellen einfach einen neuen Verweis auf die gleiche Liste. Um eine Kopie zu erstellen, müssen Sie

copy1 = sieve[:] 
2

Python hat Referenz Semantik. Im Allgemeinen bewirkt a = b, dass sich der Name a auf den gleichen Wert bezieht, auf den sich der Name b bezieht. Es erstellt oder speichert keinen neuen Wert.

Sie können eine Liste mit dem erwähnten Trick [:] klonen. Eine allgemeinere Lösung zum Kopieren von Dingen ist die Verwendung des Moduls copy.

Allerdings erfordert guter Python-Code normalerweise nicht explizit das Kopieren von Dingen sehr oft. Sie sollten sich mit der Verwendung von Listenkompressen vertraut machen, um "modifizierte Versionen" bestehender Sequenzen zu erstellen. Zum Beispiel können wir das Sieb als (ein paar andere Dinge auch zeigen):

import sys, argparse, math, itertools 

parser = argparse.ArgumentParser(description='find the largest prime factor of a number') 
parser.add_argument('n', type=int, help='number') 
args = parser.parse_args() 

# Using a loop over a 'range' to fill a list with increasing values is silly, because 
# the range *is* a list of increasing values - that's how the 'for i in ...' bit works. 
sieve = range(2, args.n + 1) 

# We don't need to remember the original loop at all. 
# Instead, we rely on each iteration of the sieve putting a new prime at the beginning. 
for index in itertools.count(): # Counting upward, 
    if index >= len(sieve): break # until we run out of elements, 
    prime = sieve[index] # we grab the next prime from the list, 
    sieve = [x for x in sieve if x == prime or x % prime != 0] # and sieve the list with it. 
# Of course, we can optimize that by checking that prime < sqrt(args.n), or whatever. 

print sieve 
+0

Es wurde mir mitgeteilt, dass Sie in Python 3.x arbeiten. In diesem Fall ist 'range' eigentlich das, was' xrange' in Python 2.x ist. Um dies zu beheben, können wir einfach etwas wie "sieve = list (range (2, args.n + 1))", explizit den Generator auflisten. –