Python 如何优化这些嵌套循环?
有人能优化这个代码块吗?它正在工作,但运行非常缓慢Python 如何优化这些嵌套循环?,python,optimization,performance,Python,Optimization,Performance,有人能优化这个代码块吗?它正在工作,但运行非常缓慢 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' + st
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
使用字典而不是列表:
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
....
使用字典而不是列表:
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
....
没有必要产生所有可能的投票。您无需生成possiblevotes
列表即可测试实际投票,因为您可以轻松计算现有投票是否可行
你也只算“留”票。寻找匹配的“继续”投票并不重要,因为任何m==n
为真的“继续”投票,m.split()[0]==n.split()[0]
也为真。因此,你不妨放弃第一个计数,只看第二个
现在您只需找到停留
投票的最大计数。使用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(投票)
次。这是一个大于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投票:
现在,您可以简单地从保留投票计数中减去赞成票(任何下降到0的计数都将被删除):
当然,您也可以一次性完成计算:
total_votes = collections.Counter()
for vote in ifilter(validvote, votes):
stay, go = vote.split()
total_votes[stay] += 1
total_votes[go] -= 1
但是,将计票结果分开可能对以后的分析很有意思。没有必要生成所有可能的选票。您无需生成possiblevotes
列表即可测试实际投票,因为您可以轻松计算现有投票是否可行
你也只算“留”票。寻找匹配的“继续”投票并不重要,因为任何m==n
为真的“继续”投票,m.split()[0]==n.split()[0]
也为真。因此,你不妨放弃第一个计数,只看第二个
现在您只需找到停留
投票的最大计数。使用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(投票)
次。这是一个大于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投票:
现在,您可以简单地从保留投票计数中减去赞成票(任何下降到0的计数都将被删除):
当然,您也可以一次性完成计算:
total_votes = collections.Counter()
for vote in ifilter(validvote, votes):
stay, go = vote.split()
total_votes[stay] += 1
total_votes[go] -= 1
但是,将选票计数分开可能对以后的分析很有意思。由于嵌套循环,代码需要很长时间。如果有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个循环:第一个循环用于导出规范化的_投票,第二个循环用于创建计数器变量。最后两个循环用于打印结果。这些循环都不是嵌套的。有人可能会说,
类的实现可能包含嵌套循环,但我相信这个类的实现是尽可能高效的计数器
- 一个重要的步骤是使选票正常化,这将大大简化计票过程。虽然我已经在一行中完成了,但您可以将其分解为几个步骤来帮助理解
- 第一步是将所有投票转换为大写:“d3 c1”变为“d3 c1”李>
- 接下来,我使用
函数将它们分解成一个列表:“D3C1”变为['D3',C1']李>split()
- 第三步是对每个项目进行排序:['D3','C1']变为['C1','D3']
- 最后一步是把它们粘在一起:['C1','D3']变成'C1 D3'
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个循环:第一个循环用于导出规范化的_投票,第二个循环用于创建计数器变量。最后两个循环用于打印结果。这些循环都不是嵌套的。有人可能会说,
类的实现可能包含嵌套循环,但我相信这个类的实现是尽可能高效的计数器
- 一个重要的步骤是使选票正常化,这将大大简化计票过程。虽然我已经在一行中完成了,但您可以将其分解为几个步骤来帮助理解
- 第一步是将所有投票转换为大写:“d3 c1”变为“d3 c1”李>
- 接下来,我使用
函数将它们分解成一个列表:“D3C1”变为['D3',C1']李>split()
- 第三步是对每个项目进行排序:['D3','C1']变为['C1','D3']
- 最后一步是把它们粘在一起:['C1','D3']变成'C1 D3'