How to perform a pairwise swap of a list? - python

I want to write a small code in python that Swap Elements in a list this program will accept a list, and will return a list that exchanges the positions of each pair of adjacent elements: positions 0 and 1, positions 2 and 3, and so on. If the list has an odd number of elements, then the element in the last position stays “in place”.
Before: [1,2,3,4,5]
After: [2,1,4,3,5]
This looks unpythonic. What is the Python way to do it?

Here is a neat one, if you are always guaranteed to have even numbers:
nums = [1,2,3,4,5,6]
print([nums[i^1] for i in range(len(nums))])
>>[2, 1, 4, 3, 6, 5]
Explanation:
print (0^1) #1
print (1^1) #0
print (2^1) #3
print (3^1) #2
print (4^1) #5
print (5^1) #4
As a refresher, the XOR has the following effect:
A B | Output
---------------
0 0 0
0 1 1
1 0 1
1 1 0
And the official description: Each bit of the output is the same as the corresponding bit in x if that bit in y is 0, and it's the complement of the bit in x if that bit in y is 1.

Most pythonic way:
def swappairwise(a):
l = len(a)&~1
a[1:l:2],a[:l:2] = a[:l:2],a[1:l:2]

Building on the answer above from #Arpegius, here a, hopefully, somewhat more readable solution. Uses the same approach.
def swap_list_pairwise(lis):
"""Pairwise swap of all elements in a list.
If the number of elements is odd, the leftover element
stays at its place.
"""
length = len(lis)
# Stop at second last if length is odd, otherwise use full list.
end = length - 1 if length % 2 else length
lis[1:end:2], lis[:end:2] = lis[:end:2], lis[1:end:2]

If you want "pythonic", try "How do you split a list into evenly sized chunks in Python?", followed by a map() that reverses every chunk. May not be too performant, though.
(Oh, forgot the flattening of the list at the end)

Here is a way:
def pairwise_swap(iterable):
for i, value in enumerate(iterable):
if i % 2 == 0:
saved = value
else:
yield value
yield saved
>>> list(pairwise_swap(range(10)))
[1, 0, 3, 2, 5, 4, 7, 6, 9, 8]

Nice approach by #Alok above. This should fix the missing last
element if the number of elements is odd.
def pairwise_swap(iterable):
"""Pairwise swap of all elements in an iterable.
If the number of elements is odd, the leftover element
stays at its place.
"""
for i, value in enumerate(iterable):
if i % 2 == 0:
saved = value
else:
yield value
yield saved
# Don't forget the last element if `iterable` has an odd
# number of elements. Since counting starts a zero, we need
# to test if `i` is even.
if iterable and i % 2 == 0:
yield value

How about trying this one out?
>>> l = [1,2,3,4,5,6]
>>> pl = [l[i:i+2] for i in range(0,len(l),2)]
>>> pl
[[1, 2], [3, 4], [5, 6]]
>>> for i in pl:
... i[0],i[1] = i[1],i[0]
... print i
...
[2, 1]
[4, 3]
[6, 5]
>>> pl
[[2, 1], [4, 3], [6, 5]]
>>>
>>> zpl = [i for sublist in pl for i in sublist]
>>> zpl
[2, 1, 4, 3, 6, 5]
>>>
I tried to resolve in the easiest way out.

It will work for both even and odd elements. if list elements are even
first part will work if not else will do his task.
a = list(input("Put your list here: "))
len_a = len(a)
last_element = len_a-1
result = 0
if len_a % 2==0:
for i in range(0, len(a), 2):
a[i], a[i + 1] = a[i + 1], a[i]
print("its if",a)
else:
a_n = a.pop()
for i in range(0, len(a), 2):
a[i], a[i + 1] = a[i + 1], a[i]
a.insert(0,a_n)
# a.insert(last_element,a_n) if you want last element remain unmodified
print("its else:",a)

This is what worked for me. Hopefully, it can help others. I think about using boxes. The value in the first position needs a temporary place to be before it can be swapped, so I assign it to x and then make the swap. Incrementing by 2 will skip over the last element, so it's okay with odd-numbered lists as well.
a = [int(s) for s in input().split()]
i = 0
while i in range(0, len(a) - 1):
x = a[i]
a[i] = a[i + 1]
a[i + 1] = x
i += 2
print(a)

Found this to be much simpler solution and handels the list with odd elements
elements = list(map(int,input().split()))
swap = []
i = 0
while i < len(elements):
if i+1 < len(elements):
swap.append(elements[i+1])
swap.append(elements[i])
else:
swap.append(elements[-1])
i = i+2
print(swap)

Related

Multiplying only odd indexes in a for loop

Multiplying only odd indexes with for loop
Why its not working?
myList = [1, 2, 3, 4, 5]
index = 0
for num in myList:
if index % 2 != 0:
num *= 2
index += 1
print(myList) # here the output still the same list
I want the output to be [1, 4, 3, 8, 5]
Edit: I see that you have edited your question, where you fixed the first issue of checking if the items in the list are odd or not. You are however still iterating over the list using for num in myList, which under the hood creates an Iterator which moves over your list. This means that whatever you do with num, you are only modifying num and not myList[index]. In order to modify the list directly, you will need to reference myList[index]. I strongly recommend you look into using enumerate, see my original answer for how to apply it to your use-case.
Your problem is that you are checking if the value inside myList is even or odd instead of its index.
Also, modifying num within the loop does not modify the value in your original list (this can easily be noticed since in the "modified" list the odd values are not multiplied).
Using the range(len()) idiom to loop over your list would yield the following code:
myList = [1, 2, 3, 4, 5]
for idx in range(len(myList)):
if idx % 2 != 0:
myList[idx] *= 2
print(myList)
You could further shorten the loop/assignment by using enumerate and list comprehension:
myList = [1, 2, 3, 4, 5]
myList = [num * 2 if idx % 2 != 0 else num for idx, num in enumerate(myList)]
print(myList)
Your way isn't working because you are not assigning 'num' back into the list.
newList = [v*2 if idx % 2 != 0 else v for idx, v in enumerate(myList)]
There are two issues in the code -
You need to check if the index is odd or even, and not the element.
Modifying num won't modify the corresponding element in the list as it does not reference the element in the list.
myList = [1, 2, 3, 4, 5]
for idx in range(len(myList)):
if idx % 2 != 0:
myList[idx]*=2

How do I mutate every third element in a list? [duplicate]

This question already has answers here:
Edit the value of every Nth item in a list
(7 answers)
how to replace every n-th value of an array in python most efficiently?
(3 answers)
Closed 3 years ago.
How do I check every third element in a list?
ie. Given the list below, I want to mutate every third item and leave the rest of the list as is.
L = [1,2,3,4,5,6,7,8,9]
Basically, if the third element in the list (in this case 3,6,9) is odd, then subtract one to make it even. If it is even, let it remain the same.
I know that if I do L[2::3] I get a new list of every third element, but I simply want to loop through every third item and check.
What would the for loop look like? I need some help.
Thanks and appreciate all help!
Don't overthink this. This is a case where list comprehensions, functions, and so on are all overkill. You need to iterate over a list, and modify it in-place, right? So you're not modifying the structure you're iterating over. The iteration target is actually the indices of the list.
xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(xs)
for idx in range(2, len(xs), 3):
if xs[idx] % 2 == 1:
xs[idx] -= 1
print(xs)
This is the equivalent of a for(i = 2; i < len(xs); i++) loop in many lower-level languages.
Compared to the list comprehension solution proposed in another answer, the for loop is marginally faster:
from timeit import timeit
def in_place(xs):
for idx in range(2, len(xs), 3):
if xs[idx] % 2 == 1:
xs[idx] -= 1
return xs
def list_comp(xs):
xs[2::3] = [i - 1 if (i % 3 == 0 and i % 2 != 0) else i for i in xs[2::3]]
return xs
# This answer is an improvement, as it eliminates one modulus
def list_comp2(xs):
xs[2::3] = [x - 1 if x % 2 else x for x in xs[2::3]]
return xs
context = {"globals": globals(), "setup": "xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]"}
print(f"For loop: {timeit('in_place(xs)', **context)}")
print(f"List comprehension: {timeit('list_comp(xs)', **context)}")
print(f"List comprehension 2: {timeit('list_comp2(xs)', **context)}")
On my machine, this produces:
For loop: 0.608657514
List comprehension: 0.7510721879999999
List comprehension 2: 0.641639047
You can just do a list comprehension using slicing to modify selected values based on condition:
L[2::3] = [x - 1 if x % 2 else x for x in L[2::3]]
Example:
L = [1,2,3,4,5,6,7,8,9]
L[2::3] = [x - 1 if x % 2 else x for x in L[2::3]]
# [1, 2, 2, 4, 5, 6, 7, 8, 8]
You can assign to slices and in this example then use a list comprehension to do the mutation.
L = [1,2,3,4,5,6,7,8,9]
L[2::3] = [ x if x % 2 == 0 else x-1 for x in L[2::3] ]
print(L)
Though despite the syntactic beauty, a simple for loop reads better for your future self and colleagues =D
Define the function you want to apply to the elements an iterate using a list comprehension
def do(number):
if number%2 == 1:
return number -1
else:
return number
[do(y) if i%3 == 0 else y for i,y in enumerate(L)]
a different solution not using enumerate explicitly could be:
for i in range(len(L)):
if i%3 == 0:
L[i] = do(L[i])
You also might want to check this about inlace operations
List comprehension is the best option:
L = [1,2,3,4,5,6,7,8,9]
L[2::3] = [i-1 if (i%3==0 and i%2!= 0) else i for i in L[2::3]
print(L)
Output:
[1, 2, 2, 4, 5, 6, 7, 8, 8]
Explanation:
Basically you look at each third element in L and see if it is divisible by 3 (remainder is 0) AND not even (mod2 is not 0) and if so subtract 1 from it, otherwise keep it as is. Replace result in the original list.

what is the issue with my code for Rearrange an array such that arr[i] = i?

I want to Rearrange an array such that each element located in its index. Or in result of program if element exist in that array: Output_array[element] = element located in its location otherwise Output_array[element] = -1.
For example if input array be :
a= [-1,-1,6,3,5,9,1,0,8,2]
then output is:
output_array= [0,1,2,3,-1,5,-1,-1,8,9]
as you see, if we ignore -1 in this array: then output_array is sorted.
this is a Python 3 code. it is printing some elements correctly, but not all
def solve(a):
n = len(a)
for i in range (n):
if i in a:
a[i] = i
else:
a[i] = -1
print(a)
a= [-1,-1,6,3,5,9,1,0,8,2]
solve(a)
Problems:
The problem is element at an index is replaced with -1 if it's not present.
When the code tries to check 5, 5 is already replaced by -1 in the previous step (a[4] = -1 (since 4 is not in the list), which is replacing 5). Similarly for the rest of the anomaly cases.
To better understand what's happening, add some prints:
def solve(a):
n = len(a)
for i in range(n):
if i in a:
a[i] = i
print(a)
print(i)
else:
a[i] = -1
print(a)
Solution:
One solution would be to use a list comprehension which does this in one line and is pretty faster:
[i if i in a else -1 for i in range(len(a))]
In function:
def solve(a):
return [i if i in a else -1 for i in range(len(a))]
And call it as:
>>> solve([-1,-1,6,3,5,9,1,0,8,2])
[0, 1, 2, 3, -1, 5, 6, -1, 8, 9]
Considering your trying to achieve an array with elements arranged into their respective index value.
The thing happening here is since the list is a mutable data type your data is being overwritten with every iteration and due to this not all values are being arranged.
for example your list after loop running from i=0 to i=3 becomes
[0,1,2,3,5,9,1,0,8,2]
You see you have lost some of your data like 6 due to changes in list,try using different list to store changes!!
The point is that when i reaches 6, 6 is no more in a, because a[2] was set to -1 when i was 2 ! You should first make a copy of a into b, and your condition should be if i in b instead of if i in a
I used another list, you could use another array, not matter.
def solve(a):
n = len(a)
c=[]
for i in range (n):
if i in a:
c.append(i)
else:
c.append(-1)
print(a)
print(c)
a= [-1,-1,6,3,5,9,1,0,8,2]
solve(a)
And output :
[-1, -1, 6, 3, 5, 9, 1, 0, 8, 2]
[0, 1, 2, 3, -1, 5, 6, -1, 8, 9]
What was issue with your code?
In this part of your code: you changed element in forward index i and be changing them, you lost them and not able to find in the remaining index of for loop.
if i in a:
a[i] = i
else:
a[i] = -1
def solve(a):
return [i if i in a else -1 for i in range(len(a))]
# Test
a = [3, 5, 0, 2, 3, 4]
print(solve(a))
Result:
[0, -1, 2, 3, 4, 5]

Slice a list in python

I have a list in python like:
l = [1,2,4,5,7,8,2,1]
I want a code that will check if the number before in the list is bigger that the next one. And if it is i want the code to remove the the number. I want my code to return [1,2,4,5,7,8] and remove the last 2 and 1.
Pseudo code:
If l[i] > l[i+1]
remove l[i+1]
then check if l[i] is bigger than the next one after that. What use to be l[i+2]
Can someone help me?
Started with your list and appended based upon your criteria to a new one.
l = [1,2,4,5,7,8,2,1]
result = []
chk = 0
for num in l:
if chk > num:
pass
else:
chk = num
result.append(num)
print result
Apparently it is bad practice to delete entries from lists within a loop , so this is a workaround.
Iterating through array if there is array[i] > array[i+1] then remove array[i+1].
array = [1,2,4,5,7,8,2,1]
l = len(array)
first = 0
secound = 1
while secound != l:
if array[first] > array[secound]:
del array[secound]
l -= 1
else:
first += 1
secound += 1
print(array)
You can use itertools groupby to find areas of lists that fulfill a condition; in this case, each number is larger than the number proceeding:
from itertools import groupby
l = [1,2,4,5,7,8,2,1]
for k, g in groupby(enumerate(l[1:],1), key=lambda (i,e): e>l[i-1]):
if k:
grp=list(g)
print l[grp[0][0]-1:grp[-1][0]+1]
# [1, 2, 4, 5, 7, 8]
This will find any area in the list that meets that condition:
l = [1,2,4,5,7,8,2,5]
for k, g in groupby(enumerate(l[1:],1), key=lambda (i,e): e>l[i-1]):
if k:
grp=list(g)
print l[grp[0][0]-1:grp[-1][0]+1]
# prints [1, 2, 4, 5, 7, 8] and [2, 5]
So break after the first if you only want 1 group:
l = [10, 11, 12, 1, 2]
for k, g in groupby(enumerate(l[1:],1), key=lambda (i,e): e>l[i-1]):
if k:
grp=list(g)
print l[grp[0][0]-1:grp[-1][0]+1]
break
# [10, 11, 12]
you can do this even in one line:
l = l[0:1] + [el for index,el in enumerate(l[0:]) if el >l[index-1]]
#l[0:1] + is ugly but i couldnt figure out another way to get the
#first element since in python l[-1] = l[len(l)-1]

How to find the smallest missing numbers from a list without using inbuilt functions or modules

Here is my list:
List = [[1,2,4,5], [1,2,3,4,5,7], [1,4,5,6], [2,3,5], [1,2,3]]
From this how to find all the smallest missing numbers?
Edit:
The "smallest missing number" is the first integer (> 0) that is not in the list.
The expected output for the example input is 3, 6, 2, 1 and 4.
The input lists are always sorted.
An approach without any built-in functions:
Lists = [[1,2,4,5],[1,2,3,4,5,7],[1,4,5,6]]
for List in Lists:
i = 1
while i <= List[-1] + 1:
if i in List:
i += 1
else:
break
print i
Basically it processes each List separately (is that what you want?). It iterates a counter i starting at 1 (assuming you look for integers > 0) and stops, as soon as List doesn't contain i.
Output:
3
6
2
If the sublists are already sorted like you input, just compare the previous to the current element, if the prev +1 is not equal to the current ele add prev + 1 to the output list:
List = [[1, 2, 4, 5], [1, 2, 3, 4, 5, 7], [1, 4, 5, 6]]
out = []
for sub in List:
prev = sub[0]
for ele in sub[1:]:
if prev + 1 != ele:
out.append(prev +1)
break
prev = ele
print(out)
[3, 6, 2]
It will work for any sublists that are ordered not just lists starting with 1:
List = [[3, 4, 5,7], [10,13,14,15], [100,101,104,105]]
Output:
[6, 11, 102]
And without slicing:
out = []
for sub in List:
prev = sub[0]
i = 0
for ele in sub:
if i == 0:
i += 1
continue
if prev + 1 != ele:
out.append(prev +1)
break
prev = ele
print(out)
If you always want to find the first missing number starting at 1 and can have 0 or negative numbers, only check each ele and increase i if the ele is > 0:
out = []
for sub in Lists:
i = 1
for ele in sub:
if ele > 0:
if ele != i:
out.append(i)
break
i += 1
print(out)
That means at worst you do a single pass over each sublist as opposed to O(n^2) approach using in
Inspired by this answer:
List = [[1,2,4,5],[1,2,3,4,5,7],[1,4,5,6]]
print [sorted(set(range(1,max(l)+2)).difference(l))[0] for l in List]
Output:
[3, 6, 2]
Sure, this approach uses built-in functions. But you can start from here and break it down by replacing forbidden functions by your own implementations.

Categories