如何修复Python嵌套循环以更快地运行?

时间:2019-01-14 13:51:19

标签: python python-3.x loops for-loop

我正在尝试编写一段代码,以从工作表中读取一些行(使用openpyxl),然后根据行中的数据和一个预先存在的列表(基于同一张表)创建一个列表。我创建了一个可以完成此工作的循环,但是当它获得更大的工作表文件时,它的速度太慢了。有没有办法使其更快?

biglist = []

rows = #some rows extracted from Excel with openpyxl

lists = [[1, 'E1000', 0], #this is just a small sample
         [1, 'F1000', 0], 
         [1, 'G1000', 4], 
         [1, 'H1000', 3], 
         [1, 'I1000', 5],
         [2, 'E1000', 1]] 

for row in rows:
        for cell in row:
            smalllist =[]
            smalllist.append(1)
            smalllist.append(cell.coordinate)
            style = 0
            for l in lists:
                for i,cl in enumerate(l):
                    if l[i][0] == smalllist[0] and l[i][1] == smalllist[1]:
                        style = l[i][2]
            smalllist.append(style)
            smalllist.append(cell.value)
            biglist.append(smalllist)

真正减慢循环速度的是这个片段:

            for l in lists:
                for i,cl in enumerate(l):
                    if l[i][0] == smalllist[0] and l[i][1] == smalllist[1]:
                        style = l[i][2]

有没有办法加快速度?我已经尝试过使用地图和列表理解功能,但是速度并不快,甚至更慢。

5 个答案:

答案 0 :(得分:1)

您没有显示styles是什么,但可以尝试从中构建映射(映射几乎具有线性查找时间),因此您无需每次都遍历styles 。也就是说,假设这部分确实是代码的瓶颈(如您在问题中所述)。

您可以在循环之前构建一个dict

styles_dict = {
    (cl[0], cl[1]): cl[2]
    for cl in s
    for s in styles}

并在外观中查找特定样式,如下所示:

style = styles_dict.get((smalllist[0], smalllist[1]))
if style is not None:
    pass

对您有用吗?

答案 1 :(得分:1)

除了Ralf的答案(这确实是要做的第一件事)之外,还有其他两种可能的微观优化方法:

首先,不要仅将smalllist创建为空,而是将其追加,而是直接填充(我假设您已经实现了Ralf的解决方案)-这样可以避免多次方法解析和调用的费用-然后使用别名{ {1}}和biglist.append(同上,避免了不断重复进行方法解析的代价):

styles_dict.get

或编写一个辅助函数来创建“小列表”并使用列表理解:

biglist = []
# local alias
append = biglist.append
get_style = styles_dict.get

for row in rows:
    for cell in row:
        # avoids a double lookup
        coords = cell.coordinate
        append([1, coords, get_style((1, coords), 0), cell.value])

您可以使用def tranform(cell): coords = cell.coordinate return [1, coords, get_style((1, coords), 0), cell.value] biglist = [transform(cell) for row in rows for cell in row] 模块来测试哪种解​​决方案更快。

答案 2 :(得分:0)

您可以使用dict来查找样式,以前两列为键:

styles = {(1, 'E1000'): 0, 
    (1, 'F1000'): 0, 
    ...}

然后像这样查找并应用您的样式...

key = (smalllist[0], smalllist[1])
style = styles[key]

对于大型样式列表,这应该更快一些,因为查找是恒定时间,而不是线性时间。

答案 3 :(得分:0)

您可以从dictionary创建一个lists并在字典中查找,而不必每次都在lists上循环-

dict_keys = [(l[0], l[1]) for l in lists]
dict_values = [l[2] for l in lists]
dict_of_lists = { k:v for (k, v) in zip(dict_keys, dict_values) }

您还可以将内部for循环替换为查找-

key = (smalllist[0], smallist[1])
try:
    style = dict_of_lists[key]
except KeyError:
    style = 0

答案 4 :(得分:-1)

尝试:

  1. 将工作表导入为Pandas数据框
  2. 将所需的任何过滤器应用于其行和列。

注意:以我的经验,您将编写更少的代码行,并且比传统的for循环运行得更快。