binbjz
binbjz

Reputation: 881

Python: swap two elements and keep the position of other special characters in a list?

Source data

lst = [1, '^', 3, 5, '!', 'a', '%', 'b', '.', 12, '*']

Desired Result:

[12, '^', 'b', 'a', '!', 5, '%', 3, '.', 1, '*']

Questions:

I want to swap two elements and keep the position of the special characters in a list.

Just swap 1 and 12, 3 and b, 5 and a. (I want to have a better efficiency)

At the same time to traversing the list from the left and right and if the two elements are not special characters, the two elements will be swapped places ?

Upvotes: 0

Views: 305

Answers (2)

JkShaw
JkShaw

Reputation: 1947

This approach produces the result that you expect:

import string

lst = [1, '^', 3, 5, '!', 'a', '%', 'b', '.', 12, '*']

# i = Start_Position, j = End_Position
i, j = 0, len(lst)-1

# Traverse while Start_Position < End_Position
while i < j:
   # Swap values at Start_Position and End_Position if not special characters and update indexes
   if str(lst[i]) not in string.punctuation and str(lst[j]) not in string.punctuation:
     lst[i], lst[j] = lst[j], lst[i]
     i += 1
     j -= 1
   # Decrease End_Position as special character found
   elif str(lst[i]) not in string.punctuation and str(lst[j]) in string.punctuation:
     j -= 1
   # Increase Start_Position as special character found
   elif str(lst[i]) in string.punctuation and str(lst[j]) not in string.punctuation:
     i += 1
   # Both values are special characters , update indexes
   else:
     i += 1
     j -= 1

print(lst)
Input : [1, '^', 3, 5, '!', 'a', '%', 'b', '.', 12, '*']

output: [12, '^', 'b', 'a', '!', 5, '%', 3, '.', 1, '*']

Upvotes: 1

FLab
FLab

Reputation: 7476

Here is my approach. The main idea is to swap a sublist of only non-special characters and then fill the output list preserving the position of the special characters.

Input:

lst = [1, '^', 3, 5, '!', 'a', '%', 'b', '.', 12, '*']

Find the position of special characters:

import string
spec_pos = [idx for idx, el in enumerate(lst) if str(el) in string.punctuation]

Get the non-special values:

to_swap = [el for idx, el in enumerate(lst) if str(el) not in string.punctuation]

Define generic function to swap elements in list, using recursion:

def rec_swap(l):
    if len(l) == 1:
        return l
    if len(l)==2:
        l[0], l[1] = l[1], l[0]
        return l
    else:
        return [l[-1]] + rec_swap(l[1:-1]) + [l[0]]

Swap elements:

swapped = rec_swap(sublist)

Create the output list:

out = []
_ = [out.append(swapped.pop(0)) if idx not in spec_pos else out.append(lst[idx]) for idx, el in enumerate(lst)]

This gives the expected output:

out
Out[60]: [12, '^', 'b', 'a', '!', 5, '%', 3, '.', 1, '*']

Upvotes: 1

Related Questions