【问题标题】:How to speed up Python script iterating nested loop?如何加速 Python 脚本迭代嵌套循环?
【发布时间】:2016-08-06 20:25:27
【问题描述】:

我正在运行一个 Python 脚本,它迭代两个巨大的列表并找到匹配的对。

但是,这似乎需要很长时间。如何加速这个脚本?

import sys
import random
import itertools

def main(args):
    target_num = int(999999999)
    num_list = range(1, target_num)
    rand_list = []
    hit_list = []

    for _ in itertools.repeat(None, target_num):
        rand_list.append(random.randint(1, target_num))

    for num in num_list:
        for rand_num in rand_list:
            if num == rand_num:
                print "hit"

if __name__ == "__main__":
    main(sys.argv[1:])

【问题讨论】:

  • 尽量不要在代码中使用内置名称作为变量名称,这可能会导致挫败感。我指的是您使用list 作为变量名
  • @Smac89 急着写一个问题,搞错了。我修改了变量名。
  • 第二个嵌套循环应该是read_list 还是rand_list
  • @Smac89 应该是 rand_list。很抱歉造成混乱。
  • 还要考虑列表理解 (rand_list = [random.randint(1, target_num) for _ in itertools.repeat(None, target_num)])。它们比使用 for 循环更有效,因为您不需要从列表中加载 append 属性并将其作为函数调用。

标签: python loops search iteration


【解决方案1】:

使用集合

import sys
import random
import itertools

def main(args):
    target_num = int(999999999)
    num_list = set(range(1, target_num))
    rand_list = []
    hit_list = []

    for _ in itertools.repeat(None, target_num):
        rand_list.append(random.randint(1, target_num))


    for num in rand_list:
        if num in num_list: # O(1)
            print "hit"

if __name__ == "__main__":
    main(sys.argv[1:])

对第一个列表使用集合,意味着检查项目是否在该列表中现在减少到 O(1)


在我写这篇文章的时候,我意识到你甚至可以做得更好。 python 3 中的range 函数返回一个序列,所以下一部分需要python 3

import sys
import random
import itertools

def main(args):
    target_num = int(999999999)
    num_list = range(1, target_num) # this is a generator
    rand_list = []
    hit_list = []

    for _ in itertools.repeat(None, target_num):
        rand_list.append(random.randint(1, target_num))


    for num in rand_list:
        if num in num_list: # Stil O(1)
            print ("hit")

if __name__ == "__main__":
    main(sys.argv[1:])

更好的是,使用范围并在第一个循环中进行检查?

for _ in itertools.repeat(None, target_num):
    rand_num = random.randint(1, target_num)
    rand_list.append(rand_num)
    if rand_num in num_list:
        print ("hit")

【讨论】:

  • O(1) 成员资格测试不是xrange 的功能,它只是在Python 3.2 when they finally finished implementing the Sequence ABC for range 中添加到rangexrange 成员资格测试一次生成并测试一个值,直到它被击中。此外,rangexrange 都不是生成器;它们或多或少是可以产生迭代器的序列对象,而不是迭代器/生成器本身;如果它们是生成器,迭代它们一次就会耗尽它们,但这不是它们的行为方式。
【解决方案2】:

如果使用 Python 2,请使用 xrange(),它会返回一个类似生成器的对象。

# requires Python 2
import random

target_num = 99 # 999999999 are too much items for testing

# target_num random numbers in range 1 .. target_num-1
random_numbers = set(random.randint(1, target_num) for _ in xrange(target_num)) 

hits = set()
for num in xrange(1, target_num):  # check for all numbers in range 1 .. target_num-1
    if num in random_numbers:   # num in set() is O(1)
        hits.add(num)

if len(random_numbers - hits) == 0:
     print "all random numbers are hits!"

# so:
for num in random_numbers:
    print num
# is the same result

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    相关资源
    最近更新 更多