对于我正在做的项目,我有兴趣创建符合以下条件的所有元组(i,j,k,z,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))
这很慢。我想可能有一种简单的方法来加快速度,我忽略了......任何想法?
答案 0 :(得分:4)
你需要更多的记忆力。很多很多的记忆。让我们看看第一个条件i == k
。满足该条件的元组数是343 ** 4 = 13841287201
。 130亿!如果每个元组只需要5*4 = 20
个字节的内存,那么该集合所需的仍然是257 GB。而这甚至不是你想要的所有元素。
所以,不,没有简单的出路。如果我要将这个问题优化到可管理的大小,我首先会问mysqlf:我真的需要一个大的列表吗?或者我可以在没有它的情况下解决这个问题吗?
答案 1 :(得分:2)
您是否希望循环次数较少且比较少。
尝试以下操作,可能会更快:
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)
答案 2 :(得分:2)
你真的不需要条件来做到这一点,
利用仅包含每个值之一的集合。
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))
编辑将值类型更改为值〜我需要更多咖啡
答案 3 :(得分:1)
由于您在尝试构造集合时内存不足,请使用生成器迭代它们而不将它们全部存储起来:
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万亿个值)。稍后会详细介绍。
如果真的出于某种特殊原因需要这个设置,你可以在这个想法的基础上定义一个" lazy"不可变集。在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()
您还可以通过考虑避免访问每个组合的方法来使迭代更有效。我能想到的最简单的是,如果i!=k
和j!=z
,则f
唯一可能的值是k
。因此,在这种情况下,不要迭代所有可能的f
,只输出可行的那个。
然而,效率最高的可能是:
f
(在这种情况下,它等于k
),或者在z
或k
中插入中间(等于i
或j
)。这些中有420亿,但这确实包含一些重复。我并不认为排除它们非常简单,但我采用的方式是按照从(0,0,0,0)
到{(344,344,344,344)
的顺序考虑所有正确的4元组。 {1}}。在输出从每个4元组生成的三个5元组中的一个之前,确定是否有任何早期的4元组可以生成它。如果是,那就跳过它。
答案 4 :(得分:1)
稍微调整一下@ 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