Python 加速字符串拆分和连接

Python 加速字符串拆分和连接,python,primes,Python,Primes,我想解决这个问题 数字197被称为循环素数,因为数字197、971和719的所有旋转本身都是素数 一百万以下有多少个循环素数 这是我的解决方案: import numpy as np def problem(n=100): circulars = np.array([], np.int32) p = np.array(sieveOfAtkin(n), np.int32) for prime in p: prime_str = str(prime)

我想解决这个问题

数字197被称为循环素数,因为数字197、971和719的所有旋转本身都是素数

一百万以下有多少个循环素数

这是我的解决方案:

import numpy as np

def problem(n=100):

    circulars = np.array([], np.int32)

    p = np.array(sieveOfAtkin(n), np.int32)
    for prime in p:
        prime_str = str(prime)
        is_circular = True
        for i in xrange(len(prime_str)):
            m = int(prime_str[i:]+prime_str[:i])
            if not m in p:
                is_circular = False

        if is_circular:
            circulars = np.append(circulars, [prime])

    return len(circulars)
不幸的是,for循环非常慢!有没有办法加快速度? 我怀疑字符串连接是瓶颈,但我不完全确定!:)


有什么想法吗?:)

  • 使用集合而不是数组进行成员资格测试。哈希查找将是O(1)而不是O(n)。这是最大的瓶颈

  • 当你看到它不是一个圆形的质数时,就立即跳出循环,而不是尝试其他旋转。这是另一个瓶颈


  • 在这里,我将循环测试隔离到一个函数中,以允许使用列表理解构建列表。把它放在函数中,一旦我们知道它不是循环的,就让它返回
    False
    。另一种选择是在
    for
    循环中执行,当我们知道它不是循环的时候,则在
    break
    中执行。然后附加到循环的
    else
    子句中的列表中。但是,一般来说,列表比较快于在循环中追加。这里可能不是这样,因为它确实增加了函数调用开销。如果你真的关心速度,那么这两种选择都值得一试

    primes = set(primes_to_one_million_however_you_want_to_get_them)
    
    def is_circular(prime, primes=primes):
       prime_str = str(prime)
       # With thanks to Sven Marnach's comments
       return all(int(prime_str[i:]+prime_str[:i]) in primes 
                  for i in xrange(len(prime_str)))
    
    
    circular_primes = [p for p in primes if is_circular(p)]
    
    我还使用了将全局变量作为默认参数传递给
    is\u circular
    函数的技巧。这意味着它可以作为局部变量而不是更快的全局变量在函数中访问

    这里有一种方法,可以在循环中使用
    else
    子句对其进行编码,以消除丑陋的标志并提高效率

    circular = []
    for p in primes:
       prime_str = str(prime)
       for i in xrange(len(prime_str)):
           if int(prime_str[i:]+prime_str[:i]) not in primes:
                break
       else:
           circular.append(p)
    

    @弧度X。阅读哈希表。答案是集合是使用哈希表实现的。这允许进行O(1)成员资格测试。对于列表或数组,成员资格测试涉及在每个元素上循环,直到找到匹配项。在最坏的情况下,如果找不到匹配项,则必须查看每个元素,使其为O(n)。@aaron:太棒了!非常感谢你!今天我确实学到了一些有用的东西:)最后四行的
    是循环的()
    可以重写为
    返回所有的(int(prime_str[I:+prime_str[:I]),在x范围内的I(len(prime_str))
    。这应该更快。@Sven捕捉得好。请参阅我的编辑。这样做,可以让您完全摆脱函数调用开销。哦,还有一句话-
    xrange
    可能从1开始,因为我们已经知道
    p
    是素数。为什么要使用字符串?不要对
    循环使用NumPy数组
    ——它有固定的大小,每次调用
    NumPy.append()
    ,都需要重新分配它。在这里,Python列表是更好的选择。(删除numpy标记,因为问题和当前答案都与numpy无关。)