Python中的反转排列

Python中的反转排列,python,permutation,Python,Permutation,我是编程新手,我正在尝试编写一个Python函数,使用以下代码查找{1,2,3,…,n}上置换的逆: def inv(str): result = [] i = list(str).index(min(list(str))) while min(list(str)) < len(list(str)) + 1: list(str)[i : i + 1] = [len(list(str)) + 1] result.append(i + 1

我是编程新手,我正在尝试编写一个Python函数,使用以下代码查找{1,2,3,…,n}上置换的逆:

def inv(str):
    result = []
    i = list(str).index(min(list(str)))
    while min(list(str)) < len(list(str)) + 1:
        list(str)[i : i + 1] = [len(list(str)) + 1]
        result.append(i + 1)
    return result
def inv(str):
结果=[]
i=列表(str).索引(最小值(列表(str)))
而min(list(str))

但是,当我尝试使用该函数时,
inv(“”)
返回
[]
。我错过什么了吗?Python跳过我的while循环是出于我不理解的语法原因吗?我在google和stackoverflow上对我想到的主题进行的搜索都没有返回任何有用的信息。

如果您只需要反向排列,可以使用

def inv(perm):
    inverse = [0] * len(perm)
    for i, p in enumerate(perm):
        inverse[p] = i
    return inverse

perm = [3, 0, 2, 1]
print(inv(perm))
for i in perm:
    print(inv(perm)[i])

[1, 3, 2, 0]
0
1
2
3

如果我有错误,请纠正我,但我认为当我将
str
更改为列表时,代码的问题就出现了:
str
是字符串,
list(str)
是字符串元素的列表。但是,由于字符串元素无法与数字进行数字比较,因此代码无法生成结果(除了
[]
)。

一个“函数式”版本:

基本上,通过排列中的指数i的值j对排列的指数i进行排序,得到所需的逆

p = [2, 1, 5, 0, 4, 3]

invert_permutation(p)
# [3, 1, 0, 5, 4, 2]

# inverse of inverse = identity
invert_permutation(invert_permutation(p)) == p
# True

也许有一个较短的方法:

def invert(p):
    return [p.index(l) for l in range(len(p))] 
以便:

perm = [3, 0, 2, 1]; print(invert(perm))
返回

[1,3,2,0]


其他答案是正确的,但值得一提的是,使用numpy有一个性能更高的替代方案:

inverse_perm = np.argsort(permutation)
编辑:下面的第四个功能更快

定时代码:

def invert_permutation_list_scan(p):
    return [p.index(l) for l in range(len(p))]

def invert_permutation_list_comp(permutation):
    return [i for i, j in sorted(enumerate(permutation), key=lambda i_j: i_j[1])]

def invert_permutation_numpy(permutation):
    return np.argsort(permutation)

def invert_permutation_numpy2(permutation):
    inv = np.empty_like(permutation)
    inv[permutation] = np.arange(len(inv), dtype=inv.dtype)
    return inv

x = np.random.randn(1000)
perm = np.argsort(x)
permlist = list(perm)
assert np.array_equal(invert_permutation_list_scan(permlist), invert_permutation_numpy(perm))
assert np.array_equal(invert_permutation_list_comp(perm), invert_permutation_numpy(perm))
assert np.array_equal(invert_permutation_list_comp(perm), invert_permutation_numpy2(perm))
%timeit invert_permutation_list_scan(permlist)
%timeit invert_permutation_list_comp(perm)
%timeit invert_permutation_numpy(perm)
%timeit invert_permutation_numpy2(perm)
结果:

82.2 ms ± 7.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
479 µs ± 9.19 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
18 µs ± 1.17 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.22 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

只是因为这里还没有人推荐它,我想应该提到的是,SymPy有一个,有一个类:

使用SymPy类可以访问大量其他有用的方法,例如使用
==
比较等效排列

您可以阅读
同理.组合学.置换
源代码


除此之外,我建议在本页上使用
np.arange
argsort
我认为反转排列
perm
的最佳方法是

pinv = sorted(range(len(perm)), key=perm.__getitem__)
这避免了重复调用
.index()
(如SeF的回答),这可能不是很有效(二次时间复杂度,而排序只需要O(n log n))

然而,请注意,这会产生一个{0,1,…,n-1}的置换,无论输入是{0,1,…,n-1}的置换还是{1,2,…,n}的置换(后者是问题中所述的)。如果输出假定为{1,2,…,n}的置换,则结果的每个元素必须增加1,例如,如下所示:

pinv = [i+1 for i in sorted(range(len(perm)), key=perm.__getitem__)]

不要给变量命名
str
;它是一个内置的。“如果有疑问,请打印更多。”我尝试将“str”重命名为“permutation”,但它仍然返回“[]”。还有其他提示吗?@Fingolfin:哦,等等,你真的在执行
inv(“”)
?然后while条件将字符串与整数进行比较,结果可能为
False
,具体取决于您使用的Python版本。例如,在Python3中,您将得到一个错误。Fingolfin,我认为您需要显示一个未经修改的文本示例,说明如何调用此函数来帮助人们解决这个问题。请注意,这是低效的,在时间上为O(len(p)^2)。好吧,如果您追求速度,那么您可以做更少的工作:`def invert_permutation_numpy2(permutation):x=np.empty_like(permutation)x[permutation]=np.arange(len(permutation),dtype=permutation.dtype)返回x`````。在迷你基准测试中,它击败了numpy排序10-20x@VF1美好的我已经编辑了我的答案以包含这个更快的函数。我认为
np.arange(len(permutation))[np.argsort(permutation)]
等于
np.argsort(permutation)
。很好。固定的!
pinv = sorted(range(len(perm)), key=perm.__getitem__)
pinv = [i+1 for i in sorted(range(len(perm)), key=perm.__getitem__)]