+r,+s的所有置换

2024-05-28 19:23:26 发布

您现在位置:Python中文网/ 问答频道 /正文

给定两个数字rs,我想得到n+-r和{}+-s的所有排列的列表。例如(使用r=3.14s=2.71

n = 1
m = 1
out = [
    (+r, +s), (+r, -s), (-r, +s), (-r, -s), 
    (+s, +r), (+s, -r), (-s, +r), (-s, -r)
    ]
^{pr2}$

使用itertools.product([+r, -r], repeat=n)我可以分别得到r和{}的列表,我只需要将它们交织在一起,但我不确定这样做是否正确。在

效率并不过分重要,所以我不介意有一个解决方案,它会产生许多重复的结果,但后来却使它们独一无二。在


Tags: 列表数字product解决方案out效率repeatitertools
3条回答

您还可以将r和{}的{}与{}和{}的{}结合起来。这样,整个结构的可读性就更好了

>>> n, m = 1, 2
>>> r, s = 3.14, 2.71
>>> [[x*i for x,i in zip(perm, prod)] for perm in permutations([r]*n + [s]*m) 
...                                   for prod in product((+1, -1), repeat=n+m)]
[[3.14, 2.71, 2.71],
 [3.14, 2.71, -2.71],
 ...
 [-2.71, -2.71, 3.14],
 [-2.71, -2.71, -3.14]]

更新:添加了通用解决方案。在

下面的解决方案在代码中稍微复杂一些,但不会产生重复的元素,并且可以延迟计算:

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)))

输出:

^{pr2}$

说明

我们可以将输出看作是包含n+/-r元素和m+/-s元素的置换,或者换句话说,n+m元素的元组,其中n是+/-r,其余的是+/-sidx包含元组,其中包含+/-r元素的所有可能位置;例如,对于第一个结果,它是(0,)。在

然后,对于这些元组中的每一个i我们在vs中创建“template”元组,它们只是大小为n+m,其中{}中的索引是r,其余的是{}。因此,对于idx中的元组(0,),您将得到(r, s, s)。如果n+m很大,您可以考虑上一步idx = map(set, idx),以获得更快的in操作,但我不确定在哪一步值得这样做。在

最后,对于v中的每个模板vi,我需要考虑对每个元素使用正值和负值的所有可能性。所以它是(+vi[0], -vi[0]), (+vi[1], -vi[1]), ...的笛卡尔积。最后,你只需要把这些产品的每一个发生器连接起来就可以得到最终的结果。在

通解

要为任意数量的不同元素构建问题的通用解决方案,需要考虑索引集的分区。例如,对于n = 3m = 5,所有可能的方法都可以将{0, 1, 2, 3, 4, 5, 6, 7}分成大小为3和5的两部分。下面是一个实现方法:

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)))

想法是一样的,您构建“模板”(这次它们包含值的索引,而不是值本身),然后从中生成笛卡尔积。在

首先使用product,然后在每个元素上使用permutations。{cd3>删除所有重复结果并传递:

arr = set(itertools.chain.from_iterable([
    itertools.permutations(x)
    for x in itertools.product(*([[+r, -r]] * n + [[+s, -s]] * m))
    ]))
print(arr)

相关问题 更多 >

    热门问题