Python 加快元组计数

Python 加快元组计数,python,performance,for-loop,counting,Python,Performance,For Loop,Counting,对于我正在做的项目,我感兴趣的是创建一个符合以下条件的所有元组(I、j、k、z、f)的列表: 所有五个变量都可以在0到343之间变化 i==k或j==z或k==f 到目前为止,我得出的结论是: z1=set() for i in xrange(344): for j in xrange(344): for k in xrange(344): for z in xrange(344): for f in xrang

对于我正在做的项目,我感兴趣的是创建一个符合以下条件的所有元组(I、j、k、z、f)的列表:

  • 所有五个变量都可以在0到343之间变化
  • i==k或j==z或k==f
到目前为止,我得出的结论是:

z1=set()
for i in xrange(344):
    for j in xrange(344):
        for k in xrange(344):
            for z in xrange(344):
                for f in xrange(344):
                    if f!=k:
                        continue
                    z1.add((i,j,k,z,f))
for i in xrange(344):
    for j in xrange(344):
        for k in xrange(344):
            for z in xrange(344):
                for f in xrange(344):
                    if z!=j:
                        continue
                    if (i,j,k,z,f) not in z1:
                        z1.add((i,j,k,z,f))
for i in xrange(344):
    for j in xrange(344):
        for k in xrange(344):
            for z in xrange(344):
                for f in xrange(344):
                    if k!=i:
                        continue
                    if (i,j,k,z,f) not in z1:
                        z1.add((i,j,k,z,f))

这很慢。我在想也许有一个简单的方法来加速这一点,我忽略了。。。有什么想法吗?

也许你想少循环,少比较

尝试以下操作,可能会更快:

def doit ():
    theRange = range (343)
    for i in theRange:
        for j in theRange:
            for k in theRange:
                cond1 = i == k
                for z in theRange:
                    cond2 = j == z
                    for f in theRange:
                        if cond1 or cond2 or k == f:
                            yield i, j, k, z, f

for x in doit ():
    doSomethingWith (x)

您可能希望减少循环和比较

尝试以下操作,可能会更快:

def doit ():
    theRange = range (343)
    for i in theRange:
        for j in theRange:
            for k in theRange:
                cond1 = i == k
                for z in theRange:
                    cond2 = j == z
                    for f in theRange:
                        if cond1 or cond2 or k == f:
                            yield i, j, k, z, f

for x in doit ():
    doSomethingWith (x)

你需要更多的记忆。很多很多的记忆。让我们看看第一个条件,
i==k
。满足该条件的元组数为
343**4=13841287201
。130亿!如果每个元组只需要
5*4=20
字节的内存,那么这个集合仍然需要257GB的内存。这甚至不是你想要的所有元素


所以,不,没有简单的出路。如果我要将这个问题优化到一个可管理的规模,我首先要问mysqlf:我真的需要这么大的列表吗?或者我可以不用它来解决这个问题吗?

您需要更多内存。很多很多的记忆。让我们看看第一个条件,
i==k
。满足该条件的元组数为
343**4=13841287201
。130亿!如果每个元组只需要
5*4=20
字节的内存,那么这个集合仍然需要257GB的内存。这甚至不是你想要的所有元素


所以,不,没有简单的出路。如果我要将这个问题优化到一个可管理的规模,我首先要问mysqlf:我真的需要这么大的列表吗?或者我可以不使用它来解决这个问题吗?

由于您试图构造集合时内存不足,请使用生成器对它们进行迭代,而不将它们全部存储:

itertools.ifilter(
    lambda x: x[0] == x[2] or x[1] == x[3] or x[2] == x[4],
    itertools.product(xrange(344), repeat=5)
)
当然,迭代仍然需要很长时间,因为还有很多事情要做(大约5万亿个值)。稍后再谈

如果你真的因为某种特殊的原因需要这个集合,你可以基于这个想法来定义一个“懒惰的”不可变集合。在Python 2中:

class MyCollection(collections.Set):
    def __contains__(self, x):
        if not isinstance(x, tuple): return False
        if not len(x) == 5: return False
        if not all(isinstance(y, int) for y in x): return False
        if not all(0 <= y <= 343 for y in x): return False
        return self.match(x)
    @classmethod
    def match(cls, x):
        return (x[0] == x[2] or x[1] == x[3] or x[2] == x[4])
    def __iter__(self):
        return itertools.ifilter(
            self.match,
            itertools.product(xrange(344), repeat=5)
        )
    def __len__(self):
        # um. Left as an exercise for the reader. About 39 billion or so.

z1 = MyCollection()
class MyCollection(collections.Set):
def___;包含______;(self,x):
如果不是isinstance(x,tuple):返回False
如果不是len(x)==5:返回False
如果不是全部(x中y的isinstance(y,int):返回False

如果不是全部(0,因为尝试构造集合时会耗尽内存,请使用生成器对它们进行迭代,而不将它们全部存储:

itertools.ifilter(
    lambda x: x[0] == x[2] or x[1] == x[3] or x[2] == x[4],
    itertools.product(xrange(344), repeat=5)
)
当然,迭代仍然需要很长的时间,因为还有很多事情要做(大约5万亿个值)。稍后将详细介绍

如果出于某种特殊原因确实需要此集合,可以基于此思想定义一个“惰性”不可变集合。在Python 2中:

class MyCollection(collections.Set):
    def __contains__(self, x):
        if not isinstance(x, tuple): return False
        if not len(x) == 5: return False
        if not all(isinstance(y, int) for y in x): return False
        if not all(0 <= y <= 343 for y in x): return False
        return self.match(x)
    @classmethod
    def match(cls, x):
        return (x[0] == x[2] or x[1] == x[3] or x[2] == x[4])
    def __iter__(self):
        return itertools.ifilter(
            self.match,
            itertools.product(xrange(344), repeat=5)
        )
    def __len__(self):
        # um. Left as an exercise for the reader. About 39 billion or so.

z1 = MyCollection()
class MyCollection(collections.Set):
def___;包含______;(self,x):
如果不是isinstance(x,tuple):返回False
如果不是len(x)==5:返回False
如果不是全部(x中y的isinstance(y,int):返回False

如果不是全部(0对@Hyboreus的代码稍作调整:

def legal_tuples():
    r = range(344)
    for i in r:
        for j in r:
            for k in r:
                i_eq_k = i == k
                for z in r:
                    if i_eq_k or j == z:
                        for f in r:
                            yield i,j,k,z,f
                    else:
                        yield i,j,k,z,k

对@Hyboreus的代码稍加修改:

def legal_tuples():
    r = range(344)
    for i in r:
        for j in r:
            for k in r:
                i_eq_k = i == k
                for z in r:
                    if i_eq_k or j == z:
                        for f in r:
                            yield i,j,k,z,f
                    else:
                        yield i,j,k,z,k

你真的不需要条件来做这件事

利用仅包含每个值中一个值的集合

a = set()
for index in xrange(344):
    for i in xrange(344):
        for j in xrange(344):
            for k in xrange(344):
                #i==k
                a.add((index,i,index,j,k))
                #j==z
                a.add((i,index,j,index,k))
                #k==f
                a.add((i,j,index,k,index))

编辑将值类型更改为值~我需要更多的咖啡

你真的不需要条件来这样做

利用仅包含每个值中一个值的集合

a = set()
for index in xrange(344):
    for i in xrange(344):
        for j in xrange(344):
            for k in xrange(344):
                #i==k
                a.add((index,i,index,j,k))
                #j==z
                a.add((i,index,j,index,k))
                #k==f
                a.add((i,j,index,k,index))


编辑将值类型更改为值~我需要更多的咖啡

这不起作用。我有点搞不清楚为什么不起作用,但例如,如果按这种方式计算范围(5)的元组你得到25个,但如果你按照我的方式,每个大循环只使用一个条件,你得到1525个。@adamlevin在py2和py3上都有限制5,这个代码段产生1525个值。@adamlevin python 2.7.5+和python3.2.4是准确的。你是对的,它确实产生1525个,但它们似乎与用我的代码创建的不匹配。我可能犯了一个错误。l让我看看其他的回答,我会回来的。@adamlevin您的顺序不同,仅此而已。这不起作用。我有点困惑,为什么它不起作用,但例如,如果您以这种方式计算范围(5)的元组你得到25个,但如果你按照我的方式,每个大循环只使用一个条件,你得到1525个。@adamlevin在py2和py3上都有限制5,这个代码段产生1525个值。@adamlevin python 2.7.5+和python3.2.4是准确的。你是对的,它确实产生1525个,但它们似乎与用我的代码创建的不匹配。我可能犯了一个错误。l让我看看其他的回答,我会回来的。@adamlevin您的顺序不同,仅此而已。+1可能您需要在func定义后面加括号。我认为
列表(范围(344))
即使在py3中也是不必要的,因为你总是要开始新的迭代。哈哈。我对我的代码也有同样的怀疑,我刚刚通过…尝试了解了这个细节,没有错误。+1也许你想要func定义后面的括号。我想
列表(范围(344))
即使在py3中也是不必要的,因为你总是要开始新的迭代。哈哈。我对我的代码也有同样的怀疑,我刚刚通过……尝试而不是错误地了解了这个细节。你的问题标题是“元组计数”但是,你的代码试图实现一个大的列表。你真正需要做什么?我想要一个tuple列表,它可能想考虑其他的东西,然后。^ ^)你的问题标题是指“元组的计数”。但是,你的代码试图实现一个大的列表。你真正需要做什么?我想要一个tuple列表,可能想考虑其他的东西,然后。