<p>首先,定义范围:</p>
<pre><code>ranges = [range(11,30), range(6,20), range(11,25)]
</code></pre>
<p>然后列举所有可能性:</p>
<pre><code>def constrainedRandoms(ranges):
answer = []
for vector in itertools.product(*ranges):
if sum(ranges) == 100:
answer.append(vector)
return answer
</code></pre>
<p>等效一层:</p>
<pre><code>answer = [v for v in itertools.product(*ranges) if sum(v)==100]
</code></pre>
<p>然后从中选择一个随机元素:</p>
<pre><code>myChoice = random.choice(answer)
</code></pre>
<p>编辑:</p>
<p>笛卡尔积(用<code>itertools.product</code>计算)本身不占用太多RAM(这是因为<code>itertools.product</code>返回一个生成器,它使用O(1)空间,但正如您所指出的,它占用了很多时间)。只有计算列表(<code>answer</code>)才可以。坏消息是,为了使用<code>random.choice</code>,您需要一个列表。如果你真的不想使用列表,那么你可能需要提出一个衰减概率函数。下面是一个非常简单的概率函数,您可以使用它:</p>
<pre><code>def constrainedRandoms(ranges):
choices = (v for v in itertools.product(*ranges) if sum(v)==100) # note the parentheses. This is now a generator as well
prob = 0.5
decayFactor = 0.97 # set this parameter yourself, to better suit your needs
try:
answer = next(choices)
except StopIteration:
answer = None
for choice in choices:
answer = choice
if random.uniform(0,1) >= prob:
return answer
prob *= decayFactor
return answer
</code></pre>
<p>衰减概率允许您增加选择符合约束的下一个向量的概率。这样想:你有很多限制。很可能,会有相对较少的向量满足这些约束。这意味着每次你决定不使用一个向量时,有另一个这样的向量的概率就会降低。因此,随着时间的推移,您需要逐渐地更偏向于将当前向量返回为“随机选择的向量”。当然,仍然可以遍历整个循环结构而不返回向量。这就是为什么代码从符合约束条件的第一个向量的默认值开始(假设存在约束条件),如果衰减概率不允许返回向量,则返回最后一个向量。<br/>
注意,这种衰减概率思想允许您不必迭代所有候选向量。随着时间的推移,代码返回所考虑的当前向量的概率增加,从而降低了代码继续并考虑其他向量的概率。因此,这个想法也有助于减轻您对运行时的担忧(不过,我很不好意思补充,不是很担心)</p>