Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Given an odd length list of values in Python, how can I swap all values other than the final value in the list?

Tags:

python

list

In regards to Python 2.7.12 (disclaimer: I understand Python2 is being phased out to Python3, but the course I'm taking started us here, perhaps to understand older code bases):

I have a list of integers whom I'd like to swap each with their neighboring value. So far, this works great for lists that are even in the number of integers they contain, however when the list length is odd, it's not so easy to simply swap each value, as the number of integers is uneven.

Giving the following code example, how can I swap all values other than the final value in the list?

arr = [1, 2, 3, 4, 5]

def swapListPairs(arr):
    for idx, val in enumerate(arr):
        if len(arr) % 2 == 0:
            arr[idx], arr[val] =  arr[val], arr[idx]  # traditional swap using evaluation order
        else:
            arr[0], arr[1] = arr[1], arr[0]  # this line is not the solution but where I know I need some conditions to swap all list values other than len(arr)-1, but am not sure how to do this?
    return arr

print swapListPairs(arr)

Bonus Points to the ultimate Pythonic Master: How can this code be modified to also swap strings? Right now, I can only use this function using integers and am very curious how I can make this work for both int and str objects?

Thank you so greatly for any insight or suggestions to point me in the right direction! Everyone's help at times here has been invaluable and I thank you for reading and for your help!

like image 668
twknab Avatar asked Dec 03 '22 14:12

twknab


2 Answers

Here's a shorter, probably faster way based on slice assignment:

def swap_adjacent_elements(l):
    end = len(l) - len(l) % 2
    l[:end:2], l[1:end:2] = l[1:end:2], l[:end:2]

The slice assignment selects the elements of l at all even indices (l[:end:2]) or all odd indices (l[1:end:2]) up to and excluding index end, then uses the same kind of swapping technique you're already using to swap the slices.

end = len(l) - len(l) % 2 selects the index at which to stop. We set end to the closest even number less than or equal to len(l) by subtracting len(l) % 2, the remainder when len(l) is divided by 2.

Alternatively, we could have done end = len(l) & ~1, using bitwise operations. That would construct an integer to use as a mask (~1), with a 0 in the 1 bit and 1s everywhere else, then apply the mask (with &) to set the 1 bit of len(l) to 0 to produce end.

like image 185
user2357112 supports Monica Avatar answered May 27 '23 20:05

user2357112 supports Monica


This is easier to do without enumerate. Note that it never, ever makes decisions based on the contents of arr; that is what makes it work on anything, not just a pre-sorted list of integers starting from 1.

for i in range(len(arr)//2):
    a = 2*i
    b = a+1
    if b < len(arr):
        arr[a], arr[b] = arr[b], arr[a]

Exercise for you: is the if actually necessary? Why or why not?

like image 34
zwol Avatar answered May 27 '23 22:05

zwol