Inverting permutations in Python
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)]
EDIT: and the fourth function below is even faster.
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)]
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)
Results:
71.7 ms ± 859 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
466 µs ± 6.37 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
21.3 µs ± 1.26 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
3.87 µs ± 69.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
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