【问题标题】:Beginner Python: How to Reduce Number of Lists in and Optimize Following Program初学者 Python:如何减少程序中的列表数量并优化以下程序
【发布时间】:2012-12-21 01:41:29
【问题描述】:

我编写了以下程序来生成未来三年我可能拥有的所有可能的时间表(我使用的是季度系统),但它的效率低得离谱,而且正如所写的那样,不会让我在下一百万年。

为了澄清,我确实已经编写了文本文件,其中指定了我感兴趣的课程以及每个季度的数字、学期和年份(例如,2013-2014 年第 1 季度秋季)。我想将其限制为每季度生成 4-5 节课的时间表,希望在程序中有所体现。

我知道,考虑到所需结果的大小,我写这篇文章的任何方式都会非常慢,但如果有人可以帮助我加快速度,或者至少给我一个估计需要多长时间完成(24 小时或 24 个月)我将非常感激。

我发现了两个问题,但我不知道如何解决:

  1. 我的比较函数(将列表转换回列表,然后在列表的每个成员中搜索另一个列表的每个成员)
  2. 一般来说,列表的广泛使用,根据我的研究,它非常占用内存(例如,我使用的组合函数会生成一个迭代器对象,根据我的研究,它应该比列表更有效,但我不知道如何有效地使用迭代器,从而减少内存使用;还有我在程序结束时使用的“GrandMasterLists”方法,结合所有双 for 循环和线性增加的调用次数每个 for 循环中的比较函数,也必须使这比它需要的效率低得多)。

以下内容很长(177 行)(尽管也是重复的),但如果您正在寻找挑战或如果您是编程专家,我将非常感谢您的帮助。

(我也意识到我在每一点上尝试做的很多事情可能都不是很透明——在很多时候我都很难想出与我想做的事情相匹配的代码-- 所以如果您需要澄清,请向我提问。)

import itertools

class Course:
    def __init__(self, NAME, TERM, YEAR):
        self.term=TERM
        self.year=YEAR
        self.name=NAME


class Quarter:
    def __init__(self, NUMBER, TERM, YEAR):
        self.term=TERM
        self.year=YEAR
        self.number=NUMBER

courselist=[]

def coursegen(NAME, TERM, YEAR):

    return Course(NAME, TERM, YEAR)

f=open('classlist.txt', 'r')
for line in f:
    courselist.append(coursegen(line.rstrip().split(';')[0],line.rstrip().split(';')    [1].split(','),line.rstrip().split(';')[2].split(','))) 
f.close()       

def quartergen(NUMBER,TERM,YEAR):
    return Quarter(NUMBER,TERM,YEAR)

m=open('quarterlist.txt', 'r')

line1=m.readline()
line2=m.readline()
line3=m.readline()
line4=m.readline()
line5=m.readline()
line6=m.readline()
line7=m.readline()
line8=m.readline()
line9=m.readline()

Quarter1=quartergen(line1.rstrip().split(';')[0],line1.rstrip().split(';')[1].split(','),line1.rstrip().split(';')[2].split(','))
Quarter2=quartergen(line2.rstrip().split(';')[0],line2.rstrip().split(';')[1].split(','),line2.rstrip().split(';')[2].split(','))
Quarter3=quartergen(line3.rstrip().split(';')[0],line3.rstrip().split(';')[1].split(','),line3.rstrip().split(';')[2].split(','))
Quarter4=quartergen(line4.rstrip().split(';')[0],line4.rstrip().split(';')[1].split(','),line4.rstrip().split(';')[2].split(','))
Quarter5=quartergen(line5.rstrip().split(';')[0],line5.rstrip().split(';')[1].split(','),line5.rstrip().split(';')[2].split(','))
Quarter6=quartergen(line6.rstrip().split(';')[0],line6.rstrip().split(';')[1].split(','),line6.rstrip().split(';')[2].split(','))
Quarter7=quartergen(line7.rstrip().split(';')[0],line7.rstrip().split(';')[1].split(','),line7.rstrip().split(';')[2].split(','))
Quarter8=quartergen(line8.rstrip().split(';')[0],line8.rstrip().split(';')[1].split(','),line8.rstrip().split(';')[2].split(','))
Quarter9=quartergen(line9.rstrip().split(';')[0],line9.rstrip().split(';')[1].split(','),line9.rstrip().split(';')[2].split(','))

m.close()   

def compare(x, y):

    if set(x).isdisjoint(set(y))==False:
    return True
else:
        return False

def offeredcoursegen(Quarter, courselist):
    offered=[]

    for course in courselist:

        if compare(course.year, Quarter.year)==True and compare(course.term, Quarter.term)==True:

            offered.append(course)

    return offered

def combo(x, courselist):   
    return list(itertools.combinations(offeredcoursegen(x,courselist), 4))+list(itertools.combinations(offeredcoursegen(x,courselist), 5))

Combo1=combo(Quarter1, courselist)

Combo2=combo(Quarter2, courselist)

Combo3=combo(Quarter3, courselist)

Combo4=combo(Quarter4, courselist)

Combo5=combo(Quarter5, courselist)

Combo6=combo(Quarter6, courselist)

Combo7=combo(Quarter7, courselist)

Combo8=combo(Quarter8, courselist)

Combo9=combo(Quarter9, courselist)

GrandMasterList=[]

for i in Combo1:
    for j in Combo2:
        if compare(i, j)==False:
            GrandMasterList.append([i,j])

GrandMasterList2=[]

for i in GrandMasterList:
    for j in Combo3:
        if compare(i[0],j)==False and compare(i[1],j)==False:
            GrandMasterList2.append(i+[j])

GrandMasterList3=[]

for i in GrandMasterList2:
    for j in Combo4:
        if compare(i[0],j)==False and compare(i[1],j)==False and    compare(i[2],j)==False:
            GrandMasterList3.append(i+[j])

GrandMasterList4=[]

for i in GrandMasterList3:
    for j in Combo5:
        if compare(i[0],j)==False and compare(i[1],j)==False and compare(i[2],j)==False and compare(i[3],j)==False:
            GrandMasterList4.append(i+[j])

GrandMasterList5=[]

for i in GrandMasterList4:
    for j in Combo6:
        if compare(i[0],j)==False and compare(i[1],j)==False and compare(i[2],j)==False and compare(i[3],j)==False and compare(i[4],j)==False:
            GrandMasterList5.append(i+[j])

GrandMasterList6=[]

for i in GrandMasterList5:
    for j in Combo7:
        if compare(i[0],j)==False and compare(i[1],j)==False and compare(i[2],j)==False and compare(i[3],j)==False and compare(i[4],j)==False and compare(i[5],j)==False:
            GrandMasterList6.append(i+[j])

GrandMasterList7=[]

for i in GrandMasterList6:
    for j in Combo8:
        if compare(i[0],j)==False and compare(i[1],j)==False and compare(i[2],j)==False and compare(i[3],j)==False and compare(i[4],j)==False and compare(i[5],j)==False and compare(i[6],j)==False:
            GrandMasterList7.append(i+[j])

GrandMasterList8=[]

for i in GrandMasterList7:
    for j in Combo9:
        if compare(i[0],j)==False and compare(i[1],j)==False and compare(i[2],j)==False and compare(i[3],j)==False and compare(i[4],j)==False and compare(i[5],j)==False and compare(i[6],j)==False and compare(i[7], j)==False:
            GrandMasterList8.append(i+[j])

for i in range(len(GrandMasterList8)):
    print 'Schedule %d \n' % (i)
    print 'Quarter 1'
    for j in range(len(GrandMasterList8[i][0])):
    print '%s ' % (GrandMasterList8[i][0][j].name)
print '\n Quarter 2'
for j in range(len(GrandMasterList8[i][1])):
    print '%s ' % (GrandMasterList8[i][1][j].name)
print '\n Quarter 3'
    for j in range(len(GrandMasterList8[i][2])):
        print '%s ' % (GrandMasterList8[i][2][j].name)
print '\n Quarter 4'
    for j in range(len(GrandMasterList8[i][3])):
        print '%s ' % (GrandMasterList8[i][3][j].name)
    print '\n Quarter 5'
    for j in range(len(GrandMasterList8[i][4])):
        print '%s ' % (GrandMasterList8[i][4][j].name)
    print '\n Quarter 6'
    for j in range(len(GrandMasterList8[i][5])):
        print '%s ' % (GrandMasterList8[i][5][j].name)
    print '\n Quarter 7'
    for j in range(len(GrandMasterList8[i][6])):
        print '%s ' % (GrandMasterList8[i][6][j].name)
    print '\n Quarter 8'
    for j in range(len(GrandMasterList8[i][7])):
        print '%s ' % (GrandMasterList8[i][7][j].name)
    print '\n Quarter 9'
    for j in range(len(GrandMasterList8[i][8])):
        print '%s ' % (GrandMasterList8[i][8][j].name)
    print '\n \n \n'

【问题讨论】:

  • 我们可以得到一个classlist.txt的例子吗?此外,假设您使用的是 python 2.x,您的类应该是:class Course(object):。此外,虽然列表不像迭代器那样内存效率高,但在我看来,在这个程序中这并不值得担心。
  • 我看到你的代码有很多冗余。
  • @Aditya Siriam 我同意。有很多部分我知道编写函数或 for 循环会更有效,但我不知道如何使它工作。我也不擅长编程。
  • @Joshua D. Boyd classlist.txt 的示例:GERMAN 209-0;S;13-14,14-15,15-16 GERMAN 309-1;F;14-15,15 -16,16-17 德语 309-2;W;14-15,15-16,16-17
  • 在你上面的python代码中,最终输出部分的缩进真的正确吗?

标签: performance list optimization memory-management python-2.7


【解决方案1】:

您发布的示例数据不够长,需要很长时间。

您可以通过以下方式分析您的程序:

python2.6 -m cProfile ./your_program.py

它会告诉你每个函数被调用的次数和一堆其他的统计数据。

在您的组合函数中,您使用两个迭代器并将它们转换为列表以返回组合列表。如果您将 combo 重写为自身是一个迭代器,那可能会给您带来一些收益。

比较可以更简单地写成:

def compare(x, y):
    return not set(x).isdisjoint(set(y))

【讨论】:

  • 我以后一定会尝试那个(-m cProfile ./programinquestion.py);这似乎是一种针对低效功能等优化任何程序的好方法。也非常感谢您对比较功能的帮助;我真的需要使用 Python 的 set 工具来改进我的设施,所以这对我有很大的帮助,并有望让我的程序运行得更快。再次感谢您的所有帮助!
  • 针对示例数据的大小,真实文件有80+行(类)长。即使每季度只有 10-20 个可能的选择,它也会产生大量的结果。例如,我尝试打印出 Combo1 的结果,并得到了大约。仅第一(九个季度)的类的可能组合就有 96000 个结果。如果我限制每个季度要考虑的类的数量,它肯定会在计算上变得更加合理,正如我通过直接测试所验证的那样,所以希望我能够限制数量选项以仅获得合理的结果
  • 换句话说,我终于意识到部分问题不仅仅是程序效率太低;它还负责处理过多的数据。通过实施您的建议并进一步限制要考虑的可能时间表的数量,我应该能够更好地工作。
【解决方案2】:

@Joshua D. Boyd
这不是答案,但由于某种原因,我无法清楚地格式化 cmets 中的 classlist.txt 示例。
无论如何,这是一个例子:

德语 209-0;S;13-14,14-15,15-16
德语 309-1;F;14-15,15-16,16-17
德语 309-2;W;14-15,15-16,16-17
真实分析 1;F;13-14,14-15,15-16,16-17
真实分析 2;W;13-14,14-15,15-16,16-17
真实分析 3;S;13-14,14-15,15-16,16-17
有机化学 1;F;13-14,14-15,15-16,16-17
有机化学 2;W;13-14,14-15,15-16,16-17
有机化学 3;S;13-14,14-15,15-16,16-17
微分几何;F;13-14,14-15,15-16,16-17
STAT 383-0;W;13-14,14-15,15-16,16-17
经济 381-1;W;13-14,14-15,15-16,16-17
数学 325-0;W;13-14,15-16

等等

当然,整个列表大约有 90 个课程,程序必须对这些课程进行排序,以得出每个季度可用的大约 10 到 20 个课程,然后为每个季度提出这些课程的所有可能组合,然后将每个季度的不重叠班级的组合组合起来(即,我不会因此得到包含同一班级多次的时间表)。

这里是 Quarterlist.txt,以防这也有帮助:
1;F;13-14
2;W;13-14
3;S;13-14
4;F;14-15
5;W;14-15
6;S;14-15
7;F;15-16
8;W;15-16
9;S;15-16

我希望这比我以前的内容更有帮助。当我在终端中使用 python 编译器运行上述程序时,甚至需要很长时间才能返回中间步骤(我在整个过程中插入了几行打印行以检查其进度,十分钟后我只得到了“组合”)。考虑到初步步骤需要多长时间才能完成,并且理论上每个“GrandMasterList”的计算时间都比上一个要长,至少在我生成它们的方式上,似乎这个程序需要花费不合理的长时间才能完成。

主要是我想提出一个更有效的方法:
比较函数
生成“GrandMasterList”的方法(即组合每个季度的所有类组合,以便每个组合的类没有重叠)

【讨论】:

  • 另外上述两个问题是相关的,因为我反复使用比较函数来生成 GrandMasterLists 但它的问题是它必须多次循环遍历整个列表,每个元素一次另一个列表,并且它在每个 GrandMasterList 中被调用的次数越来越多。所以要么我认为我要么需要让“比较”更有效率,要么我需要更有效地使用现有功能,我不确定如何继续进行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-09
  • 2013-04-17
  • 1970-01-01
相关资源
最近更新 更多