我有一个列表B = [0,0,0,0,0,0,0,0,0]但它可以是任何长度。
我试图迭代我可以通过迭代放置在B中的所有可能值。当满足某些条件C时,我想“重置”我刚迭代的元素并将下一个项目向上移动1.类似于二进制:
000变为001,但是当我们增加到002时,满足条件C,因此我们将其降为0并增加下一列:002变为010等。
很抱歉,如果我解释得不好。
所以B可能来自
B=[0,0,0,0,1,2,5]
to
B=[0,0,0,0,1,2,6]
to
B=[0,0,0,0,1,2,7]
等等。
但是当满足条件C时,我想以这种方式重置:
B=[0,0,0,0,1,2,96]
...attempt to increment
B=[0,0,0,0,1,2,97]
...attempt to increment
Condition C met
B=[0,0,0,0,1,3,0]
能够做到这一点,直到我最终击中最左边元素的条件C(相当于击中1111111并且无法再增加它)。
为了便于编码,我们假设条件C =所有数字的总和超过100。
我的尝试(按照agf的要求):
B=[0,0,0,0,0,0,0,0]
lenB=len(B)
while sum(B)<=100: #I think I have to somehow account for having tried incrementing the far left instead
B[lenB-1]+=1 #increment last value in B
while sum(B)>100: #if the sum is greater than 100
B[lenB-1]=0 #reset the far right element
B[lenB-2]+=1 #increment the next element
#but this is wrong because it needs to perform this check again and again
#for every column, while also checking if B[len-1] or B[len-2] even exists
编辑:我的条件C实际上 MUCH 比简单地检查Sum(B)&gt; 100更复杂。我只是将它用作虚拟条件,因为我可以简单地将“if sum(B)&gt; 100”替换为更复杂的条件函数。
答案 0 :(得分:3)
编辑:我似乎已经为一个不同的,更复杂的问题创建了一个解决方案。以下是我在评论中通过agf澄清的问题的解决方案:
def uphill(initial=None):
"""Yields a tuple of integers. On each iteration, add one to the last column
. If True is sent then reset the column, and begin iterating the previous
column, until the first column is matched."""
b = initial
column = len(initial)-1
while True:
if (yield tuple(b)):
b[column] = 0
if column > 0:
column -= 1
b[column] += 1
else:
yield None
raise StopIteration
yield None
else:
b[column] += 1
gen = uphill([1, 2, 0])
for b in gen:
print(b)
if sum(b) >= 4:
gen.send(True)
给我们:
(1, 2, 0)
(1, 2, 1)
(1, 3, 0)
(2, 0, 0)
(3, 0, 0)
(4, 0, 0)
我们可以使用生成器和鲜为人知的generator.send()
:
def waterfall(columns):
"""Yields a tuple of integers. On each iteration, adds one to the last list
item. The consumer can send column numbers to the waterfall during iteration
- when this is done, the specified column is reset to 0 and the previous
column is incremented. When the first column is reset, the iterator ends."""
b = [0]*columns
while True:
reset = (yield tuple(b))
if not reset == None:
while not reset == None:
b[reset] = 0
if reset > 0:
b[reset-1] +=1
else:
yield None
raise StopIteration
reset = (yield None)
else:
b[-1] += 1
gen = waterfall(3)
for b in gen:
print(b)
if b[2] >= 3:
gen.send(2)
if b[1] >= 2:
gen.send(1)
if b[0] >= 1:
gen.send(0)
这给了我们:
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 0, 3)
(0, 1, 0)
(0, 1, 1)
(0, 1, 2)
(0, 1, 3)
(0, 2, 0)
(1, 0, 0)
您可以愉快地将这些条件更改为任何内容。只需满足您选择的条件,您只需向生成器发送要重置的列的索引(自动将其上方的值增加1)。重置最后一列时,它将完成生成器。
值得注意的是,您可以随时使用gen.close()
来停止它,而无需到达最后一列。 (gen.send(0)
与gen.close()
)相同。
具有不同条件的示例:
gen = waterfall(2)
for b in gen:
print(b)
if sum(b) >= 3:
gen.send(1)
if b[0] >= 3:
gen.send(0)
给我们:
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 1)
(1, 2)
(2, 0)
(2, 1)
(3, 0)
答案 1 :(得分:1)
def increment(box, condition):
# last index in the list
maxindex = index = len(box) - 1
while True:
# so you can see it's correct
print box
# increment the last digit
box[-1] += 1
# while the overflow condition is True
while condition(box):
# reset the current digit
box[index] = 0
# and move to the next index left
index -= 1
# if we're past the end of the list
if index < 0:
# stop
return
# increment the current digit
box[index] += 1
# back to the rightmost digit
index = maxindex
increment([0] * 3, lambda box: sum(box) > 4)
答案 2 :(得分:0)
您可以使用列表推导和range()
(在此处使用小值来停止输出非常大)来执行此操作:
>>> [(a, b, c) for a in range(2) for b in range(4) for c in range(3)]
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 3, 0), (0, 3, 1), (0, 3, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 3, 0), (1, 3, 1), (1, 3, 2)]
请注意,如果您想循环它,而不是在开头生成一个大列表,使用生成器表达式只会根据需要创建项目:
for a, b, c in ((a, b, c) for a in range(2) for b in range(4) for c in range(3)):
...
请注意,在Python 2.x中,您需要使用xrange()
而不是range
来获取生成器而不是列表。
答案 3 :(得分:0)
这样做你想要的吗?
B=[0,1,0]
def check(ll,callback):
"""
This function only works if you
increment the last element in the list.
All other incrementing is done in this function.
"""
for idx in reversed(range(len(ll))):
if(callback(ll)):
ll[idx]=0
ll[idx-1]+=1
else:
break #this index wasn't updated, so the next one won't be either.
#a check to see if every element is 1
return all(map(lambda x: x==1,ll))
def checksum(ll):
return True if sum(ll)>100 else False
count=0
while True:
count+=1
B[-1]+=1
if(check(B,checksum)): break
print B
print B # [1,1,1]
print count
即使对于这个例子,我们在[1,1,1]
之前经历了超过5000次迭代修改强>
添加了一个简单的break
语句,因为只要在上一次迭代期间更改了列表,就必须检查该列表。
答案 4 :(得分:0)
紧凑但效率低下的解决方案
如果您的条件不是特定于数字的,请尝试使用类似于LattyWare的解决方案,但使用过滤器仅提供预测结果。
如果您有一个谓词函数列表,将(a, b, c)
映射到bool
for a, b, c in ((a, b, c) for a in range(2) for b in range(4) for c in range(3)):
if all [p(a,b,c) for p in predicates]:
yield a, b, c
请注意,如果您无法对各个数字设置合理的初始界限(搜索空间变得太大),则会变得站不住脚。
答案 5 :(得分:0)
这似乎可以解决您所期望的递增问题:
b=[0,0,0,0,0,0,0,1,7]
def incr(arr, condition, pred):
arr[-1] += 1
element = -1
while condition(arr) > pred:
if arr[element]:
arr[element] = 0
arr[element-1] += 1
else:
element -= 1
if abs(element) == len(arr):
break
return arr
print b
for i in xrange(0,10):
b = incr(b, sum, 15)
print b
函数接受列表和函数条件(例如,sum)以及增量应该结转的点。
因此它为示例sum(15)返回这样的结果:
>>>
[0, 0, 0, 0, 0, 0, 0, 1, 7]
[0, 0, 0, 0, 0, 0, 0, 1, 8]
[0, 0, 0, 0, 0, 0, 0, 1, 9]
[0, 0, 0, 0, 0, 0, 0, 1, 10]
[0, 0, 0, 0, 0, 0, 0, 1, 11]
[0, 0, 0, 0, 0, 0, 0, 1, 12]
[0, 0, 0, 0, 0, 0, 0, 1, 13]
[0, 0, 0, 0, 0, 0, 0, 1, 14]
[0, 0, 0, 0, 0, 0, 0, 2, 0]
[0, 0, 0, 0, 0, 0, 0, 2, 1]
[0, 0, 0, 0, 0, 0, 0, 2, 2]