Python how to revert the pattern of a list rearrangement
Asked Answered
L

3

6

So I am rearranging a list based on an index pattern and would like to find a way to calculate the pattern I need to revert the list back to its original order.

for my example I am using a list of 5 items as I can work out the pattern needed to revert the list back to its original state.

However this isn't so easy when dealing with 100's of list items.

def rearrange(pattern: list, L: list):
    new_list = []
    for i in pattern:
        new_list.append(L[i-1])
    return new_list

print(rearrange([2,5,1,3,4], ['q','t','g','x','r']))

#['t', 'r', 'q', 'g', 'x']

and in order to set it back to the original pattern I would use

print(rearrange([3,1,4,5,2],['t', 'r', 'q', 'g', 'x']))
#['q', 't', 'g', 'x', 'r']

What I am looking for is a way to calculate the pattern "[3,1,4,5,2]" regarding the above example. whist running the script so that I can set the list back to its original order.

Using a larger example:

print(rearrange([18,20,10,11,13,1,9,12,16,6,15,5,3,7,17,2,19,8,14,4],['e','p','b','i','s','r','q','h','m','f','c','g','d','k','l','t','a','n','j','o']))
#['n', 'o', 'f', 'c', 'd', 'e', 'm', 'g', 't', 'r', 'l', 's', 'b', 'q', 'a', 'p', 'j', 'h', 'k', 'i']

but I need to know the pattern to use with this new list in order to return it to its original state.

print(rearrange([???],['n', 'o', 'f', 'c', 'd', 'e', 'm', 'g', 't', 'r', 'l', 's', 'b', 'q', 'a', 'p', 'j', 'h', 'k', 'i']))
#['e','p','b','i','s','r','q','h','m','f','c','g','d','k','l','t','a','n','j','o']
Likely answered 21/3, 2022 at 21:13 Comment(2)
What are the inputs to the function?Dehydrogenate
In your first call rearrange [2,5,1,3,4], find the index of 1, put it in a list, find the index of 2, append it to the list, repeat... You'll end up with the argument to your second call: [3,1,4,5,2] -- don't actually do it this way, but that's how you'd find the inverse.Dwain
W
2

This is commonly called "argsort". But since you're using 1-based indexing, you're off-by-one. You can get it with numpy:

>>> pattern
[2, 5, 1, 3, 4]
>>> import numpy as np
>>> np.argsort(pattern) + 1
array([3, 1, 4, 5, 2])

Without numpy:

>>> [1 + i for i in sorted(range(len(pattern)), key=pattern.__getitem__)]
[3, 1, 4, 5, 2]
Willowwillowy answered 21/3, 2022 at 21:21 Comment(2)
What about without Numpy? I don't think OP wants an external library.Ruler
@Ruler added a pure-python version.Willowwillowy
C
1

What about something like below:


def revert_pattern(pattern):
    pattern_i = [0]*len(pattern)

    for k in range(len(pattern)):
        pattern_i[pattern[k]-1] = k+1 

    return pattern_i

print(revert_pattern([2, 5, 1, 3, 4]))
# [3, 1, 4, 5, 2]

Note: I followed your logic but I recommend you using 0 as the smallest indexes instead of 1 since it requires somes extra +1/-1 that could be avoided

Chamois answered 21/3, 2022 at 21:26 Comment(0)
D
0
def rearrange(p, l):
    arr = [l[i - 1] for i in p]
    d = {v : i + 1 for i, v in enumerate(arr)}
    order = [d[k] for k in l]
    return arr, order

a = [2, 5, 1, 3, 4]
b = ['q', 't', 'g', 'x', 'r']
rearrange(a, b)
# (['t', 'r', 'q', 'g', 'x'], [3, 1, 4, 5, 2])

OR maybe

def revert(p):
    z = zip(p, list(range(len(p))))
    return [x + 1 for _, x in sorted(z)]

a = [2, 5, 1, 3, 4]   
revert(a)
# [3, 1, 4, 5, 2]
Donation answered 21/3, 2022 at 21:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.