Inverting permutations in Python

蓝咒 提交于 2019-12-23 12:09:30

问题


I'm new to programming, and I'm trying to write a Python function to find the inverse of a permutation on {1,2,3,...,n} using the following code:

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

However, when I try to use the function, inv('<mypermutation>') returns []. Am I missing something? Is Python skipping over my while loop for some syntactical reason I don't understand? None of my google and stackoverflow searches on topics I think of are returning anything helpful.


回答1:


If you only want the inverse permutation, you can use

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



回答2:


Other answers are correct, but for what it's worth, there's a much more performant alternative using numpy:

inverse_perm = np.arange(len(permutation))[np.argsort(permutation)]

Timing code:

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.arange(len(permutation))[np.argsort(permutation)] 

x = np.random.randn(10000)
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))
%timeit invert_permutation_list_scan(permlist)
%timeit invert_permutation_list_comp(perm)
%timeit invert_permutation_numpy(perm)

Results:

7.16 s ± 109 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
6.18 ms ± 45.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
524 µs ± 8.93 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)



回答3:


Correct me if I have this wrong, but I think the problem with my code comes when I change str to a list: str is a string, and list(str) is a list of string elements. However, since string elements can't be numerically compared to numbers, the code fails to produce a result (other than []).




回答4:


A "functional style" version:

def invert_permutation(permutation):
    return [i for i, j in sorted(enumerate(permutation), key=lambda (_, j): j)]

Basically, sorting the indices i of the permutation by their values j in the permutation yields the desired inverse.

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



回答5:


Just since no one has recommended it here yet, I think it should be mentioned that SymPy has an entire combinatorics module, with a Permutation class:

from sympy.combinatorics import Permutation
o = [3, 0, 2, 1]
p = Permutation(o)
inv = p.__invert__()
print(inv.array_form) # [1, 3, 2, 0]

Using the SymPy class gives you access to a whole lot of other useful methods, such as comparison between equivalent permutations with ==.

You can read the sympy.combinatorics.Permutation source code here.

Other than that, I would recommend the answer on this page using np.arange and argsort.




回答6:


Maybe there is a shorter way:

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

so that:

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

returns

[1,3,2,0]



来源:https://stackoverflow.com/questions/9185768/inverting-permutations-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!