任何人都可以优化此代码块吗?它正在运行,但运行速度很慢。
maxsat = 0
possiblevotes = []
for i in range(1,int(numcats)+1):
for j in range(1,int(numdogs)+1):
possiblevotes.append('C' + str(i) + ' ' + 'D' + str(j))
possiblevotes.append('D' + str(j) + ' ' + 'C' + str(i))
for m in possiblevotes:
count = 0
for n in votes:
if m == n:
count += 1
elif m.split()[0] == n.split()[0]:
count += 1
if count > maxsat:
maxsat = count
答案 0 :(得分:1)
无需生成所有可能的投票。您可以测试实际投票而无需生成possiblevotes
列表,因为您可以轻松计算现有投票是否可行。
你也只是真正计算'留下'的选票。您寻找匹配的“留下来”投票并不重要,因为m == n
为真的任何“留下来”投票,m.split()[0] == n.split()[0]
也为真。所以你可以放弃第一个计数,只看第二个。
现在您只是找到stay
票的最大数量。使用collections.Counter()
可以更轻松地计算:
import collections
vote_counts = collections.Counter(v.split()[0] for v in votes)
maxsat = vote_counts.most_common(1)[0][1] # retrieve the most popular count
这会计算您的代码计算的相同数字,但现在我们只需要遍历一次的投票,并且只计算'留'投票。
将此与您的循环进行对比,首先循环numcats * numdogs
次,然后循环numcats * numdogs * 2 * len(votes)
次。因果3 * numcats * numdogs
更大。
如果您必须先验证投票,可以使用:
from itertools import ifilter
numcats = int(numcats)
numdogs = int(numdogs)
def validvote(vote):
stay, go = vote.split()
cat, dog = sorted((stay, go))
if (cat[0], dog[0]) != ('C', 'D'):
return False
if not (1 >= int(cat[1:]) >= numcats):
return False
if not (1 >= int(dog[1:]) >= numdogs):
return False
return True
vote_counts = collections.Counter(v.split()[0] for v in ifilter(validvote, votes))
您也可以开始使用 go 投票:
stay_votes = collections.Counter()
go_votes = collections.Counter()
for vote in ifilter(validvote, votes):
stay, go = vote.split()
stay_votes[stay] += 1
go_votes[go] += 1
现在你可以简单地减去来自逗留投票数的投票数(任何数据都会被删除):
total_votes = stay_votes - go_votes
# Display top 10
for creature, tally in total_votes.most_common(10):
print('{}: {:>#5d}'.format(creature, tally))
当然,你也可以一次性完成计算:
total_votes = collections.Counter()
for vote in ifilter(validvote, votes):
stay, go = vote.split()
total_votes[stay] += 1
total_votes[go] -= 1
但保持投票结果分开可能对以后的分析很有意思。
答案 1 :(得分:0)
使用字典而不是列表:
possiblevotes = {}
for i in range(1,int(numcats)+1):
for j in range(1,int(numdogs)+1):
possiblevotes['C' + str(i) + ' ' + 'D' + str(j)] = 0
possiblevotes['D' + str(j) + ' ' + 'C' + str(i)] = 0
for n in votes:
possiblevotes[n] += 1
....
答案 2 :(得分:0)
由于嵌套循环,代码需要很长时间。如果你有1000只猫,1000只狗和1000票,那么第一组循环运行1000x1000次;第二组运行1000x1000x1000次。如果我们可以删除嵌套循环,那么代码将运行得更快。
我注意到你似乎记录了投票,其中'C1 D3'与'D3 C1'相同。我建议你使用collections模块中的Counter类来完成繁重的工作。这是我的解决方案:
import collections
if __name__ == '__main__':
votes = ['C1 D3', 'D1 C5', 'D3 C1', 'd1 c1', 'c1 d3'] # Example votes
# Normalize the votes: 'D3 C1' becomes 'C1 D3',
# 'c1 d3' becomes 'C1 D3'
normalized_votes = [''.join(sorted(v.upper().split())) for v in votes]
# Count the votes
counter = collections.Counter(normalized_votes)
# Top 10
print '--- TOP 10 ---'
for vote, count in counter.most_common(10):
print count, vote
# Or print all
print '--- ALL ---'
for vote, count in counter.iteritems():
print count, vote
此解决方案使用4个循环:第一个是派生 normalized_votes ,第二个是创建计数器变量。最后两个循环处理打印结果。这些循环都不是嵌套的。有人可能会争辩说Counter
类的实现可能包含嵌套循环,但我相信这个类的实现尽可能高效。
一个重要的步骤是规范投票,这应该大大简化你的统计。虽然我已经在一行中完成了它,但您可以将其分解为几个步骤以帮助理解。
split()
功能的列表:'D3 C1'变为['D3','C1']。 答案 3 :(得分:0)
import re
vote_pattern = re.compile('^(C|D)\d+\s')
votes = ['123', 'A1123', 'cC32', 'C', 'D0', 'C11']
maxsat = sum(0 if vote_pattern.match(vote) is None else 1 for vote in votes)
当然,你可以将这个可怕的数字改为过滤器。