2

我正在尝试使用方法生成素数列表。我需要遍历每个数字 2...n 并检查它是否是 2...n 的倍数。出于某种原因,错误的列表似乎正在被修改。

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

我收到以下错误:

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'
4

5 回答 5

7

你不是在复制。您正在使用引用,所以copy1,copy2copy3都引用同一个列表 -- sieve。如果要复制,请使用:

copy1 = sieve[:]

这将创建一个副本sieve并将其分配给copy1.

于 2010-12-02T16:13:39.633 回答
2

你需要使用

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

实际复制列表。否则,您只需复制对列表的引用。

>>> a = [1,2]
>>> b = a
>>> c = a[:]
>>> b[0] = 0
>>> c[0] = 3
>>> a
[0, 2]
>>> b
[0, 2]
>>> c
[3, 2]
于 2010-12-02T16:14:27.513 回答
2
copy1 = sieve
copy2 = sieve
copy3 = sieve

这些不是副本,它们是参考。

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

是一种很好的筛法

更多单元测试,因为它很有趣

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
于 2010-12-02T16:17:32.157 回答
2

Python 具有引用语义。通常,a = b导致名称a引用该名称b当前引用的相同值。它不会创建或存储新值。

您可以使用提到的 [:] 技巧克隆列表。用于复制内容的更通用的解决方案是使用copy模块。

但是,好的 Python 代码通常不需要显式地频繁地复制内容。您应该熟悉使用列表推导来创建现有序列的“修改版本”。例如,我们可以将筛子实现为(也展示一些其他的东西):

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
于 2010-12-02T16:32:19.563 回答
1

我无法对此进行测试,因为我没有 Python 3.2 的副本(argparse在 Python 3.2 中是新的),但我想到了两件明显的事情:

首先,您确实需要做sieve.append(int(i)).

其次,您不是在制作 sieve 的副本,您只是在创建对同一列表的新引用。要制作副本,您需要

copy1 = sieve[:]
于 2010-12-02T16:19:30.587 回答