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”
  • 接下来,我使用
    split()
    函数将它们分解成一个列表:“D3C1”变为['D3',C1']
  • 第三步是对每个项目进行排序:['D3','C1']变为['C1','D3']
  • 最后一步是把它们粘在一起:['C1','D3']变成'C1 D3'

由于嵌套循环,代码需要很长时间。如果有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”
  • 接下来,我使用
    split()
    函数将它们分解成一个列表:“D3C1”变为['D3',C1']
  • 第三步是对每个项目进行排序:['D3','C1']变为['C1','D3']
  • 最后一步是把它们粘在一起:['C1','D3']变成'C1 D3'
当然,你可以把这个糟糕的总数改成类似过滤器的东西

你可以