更新:添加了一般解決方案。
這裏是一個解決方案,是比較複雜一點在代碼,但不會產生重複的元素,並且可以懶惰地評估:
from itertools import combinations, product, chain
r = 3.14
s = 2.71
n = 1
m = 2
idx = combinations(range(n + m), n)
vs = ((r if j in i else s for j in range(n + m)) for i in idx)
res = chain.from_iterable(product(*((+vij, -vij) for vij in vi)) for vi in vs)
print("\n".join(map(str, res)))
輸出:
(3.14, 2.71, 2.71)
(3.14, 2.71, -2.71)
(3.14, -2.71, 2.71)
(3.14, -2.71, -2.71)
(-3.14, 2.71, 2.71)
(-3.14, 2.71, -2.71)
(-3.14, -2.71, 2.71)
(-3.14, -2.71, -2.71)
(2.71, 3.14, 2.71)
(2.71, 3.14, -2.71)
(2.71, -3.14, 2.71)
(2.71, -3.14, -2.71)
(-2.71, 3.14, 2.71)
(-2.71, 3.14, -2.71)
(-2.71, -3.14, 2.71)
(-2.71, -3.14, -2.71)
(2.71, 2.71, 3.14)
(2.71, 2.71, -3.14)
(2.71, -2.71, 3.14)
(2.71, -2.71, -3.14)
(-2.71, 2.71, 3.14)
(-2.71, 2.71, -3.14)
(-2.71, -2.71, 3.14)
(-2.71, -2.71, -3.14)
說明
我們可以將輸出看作包含n
+/- r
e的排列lements和m
+/- s
元件,或者,換句話說,的n
+ m
元素,其中n
是+/- r
,其餘元組是+/- s
。 idx
包含具有+/- r
元素的所有可能位置的元組;例如,第一個結果是(0,)
。
然後,對每個這些元組i
我們創造vs
「模板」的元組,這只是大小的元組n
+ m
其中i
指數r
,其餘爲s
。因此,對於idx
中的元組(0,)
,您將獲得(r, s, s)
。如果n
+ m
是非常大的,你可以考慮前面的步驟idx = map(set, idx)
一個更快in
操作,但我不知道在這一點,將是值得的。
最後,對於這些模板中的每一個vi
在v
我需要考慮所有可能性,爲它的每個元素使用正值和負值。所以它是(+vi[0], -vi[0]), (+vi[1], -vi[1]), ...
的笛卡爾積。最後,你只需要鏈接每個這些產品的每一個發電機來獲得最終結果。
通用的解決方案
要建立不同的元素任意數量的問題的通用解決方案,你需要考慮分區索引集的。例如,對於n = 3
和m = 5
,所有可能的方式,你可以在尺寸3和5這裏分爲兩個部分{0, 1, 2, 3, 4, 5, 6, 7}
是一個實現:
from itertools import chain, repeat, permutations, product
def partitions(*sizes):
if not sizes or all(s <= 0 for s in sizes):
yield()
for i_size, size in enumerate(sizes):
if size <= 0:
continue
next_sizes = sizes[:i_size] + (sizes[i_size] - 1,) + sizes[i_size + 1:]
for p in partitions(*next_sizes):
yield (i_size,) + p
def signed_permutations(*elems):
values, sizes = zip(*elems)
templates = partitions(*sizes)
return chain.from_iterable(
product(*((+values[ti], -values[ti]) for ti in t)) for t in templates)
r = 3.14
s = 2.71
n = 1
m = 2
res = signed_permutations((r, n), (s, m))
print("\n".join(map(str, res)))
的想法是一樣的,你建的「模板「(這次他們包含價值指數而不是價值本身),然後是笛卡爾產品。
這似乎不工作:'list(itertools.product(*([[+ r,-r]] * 1 + [[ (3.14,2.71),(3.14,-2.71),(-3.14,2.71),(-3.14,-2.71)]' - '3.14'從來沒有排在第二位。 –
@NicoSchlömerOhh對不起,我誤讀了您的示例輸出 – jdehesa
一兩個解釋無疑有助於理解代碼。 –