Why does my loop rotate only once? - python

I'm supposed to write a function which gets a list and rotates it several times (number of rotation is given)
def rotate1(lst):
print(lst[-1:]+lst[:-1])
def rotatek_v1(lst,k):
for i in range(0,k):
rotate1(lst)
print(lst)
for some reason, in the second function it rotates only once but I need it to rotate k times (I need it to run the function rotate1 k times), what should I fix?
Thanks

You need to assign the value back
def rotate1(lst):
return lst[-1:]+lst[:-1] # here
def rotatek_v1(lst,k):
for i in range(0,k):
lst = rotate1(lst) # and here
print(lst)

You are not modifying any value, you are just printing, so each time you iterate, you will get the same value. You have to use the return statement, so you can use the result and assign it to a variable, like:
def some_function():
return 100
some_var = some_function()
Applying it to your case:
def rotate1(lst):
return (lst[-1:] + lst[:-1])
def rotatek_v1(lst, k):
for i in range(0, k):
lst = rotate1(lst)
print lst
Demo:
>>> rotatek_v1([1, 2, 3, 4, 5], 6)
>>> [5, 1, 2, 3, 4]
[4, 5, 1, 2, 3]
[3, 4, 5, 1, 2]
[2, 3, 4, 5, 1]
[1, 2, 3, 4, 5]
[5, 1, 2, 3, 4]

Correct code should be this -
def rotate1(lst):
print(lst[-1:]+lst[:-1]);
def rotatek_v1(lst,k):
for i in range(0,k): rotate1(lst);
print(lst);

You have to align print statement in first function in right way like this
def rotate1(lst):
print(lst[-1:]+lst[:-1])
and in case of return then
def rotate1(lst):
return (lst[-1:]+lst[:-1])

Related

How to insert an element in a list after using del in python

def my_len(lst):
mylen = 0
for i in lst:
mylen += 1
return mylen
def insrt(lst, what, where):
length = my_len(lst)
tmp = [0] * (length + 1)
for i in range(0, where):
tmp[i] = lst[i]
tmp[where] = what
for i in range(where, length + 1):
tmp[i] = lst[i - 1]
return tmp
def move(lst, from_index, to_index):
a = lst[from_index]
del lst[from_index]
insrt(lst, a, to_index)
return lst
my intention was if the original list input is [1, 2, 3, 4, 5, 6], then print(move(lst, 3, 1) will give [1, 4, 2, 3, 5, 6], but my code gives [1, 2, 3, 5, 6]. Please explain how to fix it.
NB. See the end of the answer for an alternative interpretation of the move
If you want the item to end up in the defined to_index, you can simply use list.insert and list.pop:
def move(lst, from_index, to_index):
lst.insert(to_index, lst.pop(from_index))
examples:
l = [1, 2, 3, 4, 5, 6]
move(l, 1, 3)
print(l)
[1, 3, 4, 2, 5, 6]
l = [1, 2, 3, 4, 5, 6]
move(l, 3, 1)
print(l)
[1, 4, 2, 3, 5, 6]
l = [1, 2, 3, 4, 5, 6]
move(l, 3, 3)
print(l)
[1, 2, 3, 4, 5, 6]
NB. your function should probably either return a copy, or modify the list in place, not both. (here I chose to modify in place, see below for a variant).
copy variant:
def move(lst, from_index, to_index):
lst = lst.copy()
lst.insert(to_index, lst.pop(from_index))
return lst
l = [1, 2, 3, 4, 5, 6]
l2 = move(l, 1, 3)
print(l)
[1, 2, 3, 4, 5, 6]
print(l2)
[1, 3, 4, 2, 5, 6]
alternative interpretation: move to the position as defined before the move
In this different interpretation, the item moves to the position as defined if the insertion occured before the deletion.
In this case we need to correct the insertion position if it is greater than the initial position.
We can take advantage of the boolean/integer equivalence by subtracting to_index>from_index (1 if True, 0 otherwise)
def move(lst, from_index, to_index):
lst.insert(to_index-(to_index>from_index), lst.pop(from_index))
l = [1, 2, 3, 4, 5, 6]
move(l, 1, 3)
print(l)
# [1, 3, 2, 4, 5, 6]
This would work,
def move(lst, from_index, to_index):
new_lst = lst[:to_index] + [lst[from_index]] + [item for item in lst[to_index:]]
new_lst.pop(from_index + 1)
return new_lst
lst = [1, 2, 3, 4, 5, 6]
move(lst, 3, 1)
Output -
[1, 4, 2, 3, 5, 6]
The main problem you're seeing right now relates to how your insrt function works, as compared to how you're calling it.
The way you've written it, insert returns a new list containing the values from the old list plus one new value at a particular index. But when you call it in move, you seem to be expecting it to modify the given list in place. It doesn't do that. You need to change at least one of the two functions so that they match up. Either make insrt work in-place, or make move save the value returned by it rather than throwing it away.
Anyway, here's a very simple tweak to your move function that makes it work properly with the insrt function as you've shown it:
def move(lst, from_index, to_index):
a = lst[from_index]
del lst[from_index]
new_lst = insrt(lst, a, to_index) # save the new list after the insert
return new_lst # and then return it
I'd note that using del on the earlier line already modifies the lst passed in, so this design may not make a whole lot of sense. You might want to modify insrt to work in place instead, to be consistent. That would look something like this (which would work with your original move):
def insrt(lst, what, where):
length = my_len(lst)
lst.append(None) # add a dummy value at the end of the list
for i in range(length-1, where, -1): # iterate backwards from the end
lst[i] = lst[i - 1] # shift each value back
lst[where] = what # plug in the new value
# no return any more, this version works in place

python swap function without return statement

def swapPositions(list, pos1, pos2):
list[pos1], list[pos2] = list[pos2], list[pos1]
return list
seq=['abd','dfs','sdfs','fds','fsd','fsd']
print(swapPositions(seq,2,3))
Can we do this without the return statement?
list object in python is a mutable object which means that it gets passed into functions by reference, not by value. So, you are already changing seq in-place and there is no need to the return statement.
def swapPositions(list, pos1, pos2):
list[pos1], list[pos2] = list[pos2], list[pos1]
seq=['abd','dfs','sdfs','fds','fsd','fsd']
swapPositions(seq,2,3)
print(seq)
# returns ['abd', 'dfs', 'fds', 'sdfs', 'fsd', 'fsd']
Python functions usually follow two conventions:
Return a new object, leaving the argument unchanged.
Modify the argument in place, and return None.
Your function does the latter, and should omit the return statement.
>>> x = [1, 2, 3, 4]
>>> swapPositions(x, 2, 3)
>>> x
[1, 2, 4, 3]
If you opt for the former, x should be left alone
def swapPositions(L, pos1, pos2):
L = L.copy()
L[pos1], L[pos2] = L[pos2], L[pos1]
return L
>>> x = [1, 2, 3, 4]
>>> swapPositions(list, 2, 3)
[1, 2, 4, 3]
>>> x
[1, 2, 3, 4]

How to fix python recursion function

I am trying to write a recursive function which returns a copy of a list where neighbouring elements have been swapped. For example, swapElements([2, 3, 4, 9]) would return [3, 2, 9, 4].
This is my code as of now:
def swapElements(mylist):
if len(mylist) == 1:
pass
if len(mylist) == 2:
mylist[0], mylist[1] = mylist[1], mylist[0]
else:
mylist[0], mylist[1] = mylist[1], mylist[0]
swapElements(mylist[2:])
return mylist
When I run this function it only returns the list with the first two elements swapped, does anyone know why this function is not swapping any other elements other than the first two and how I could fix it?
In your question it says you wish to return a copy. Your function mutates mylist in-place. Additionally, pass has a return value of None. You can simplify the function like so -
def swap (a = []):
if len(a) < 2:
return a
else:
return [ a[1], a[0] ] + swap(a[2:])
print(swap([2, 3, 4, 9]))
# [2, 3, 4, 9]
print(swap([2, 3, 4, 9, 6]))
# [2, 3, 4, 9, 6]
print(swap([1]))
# [1]
print(swap())
# []
I would let the recursion do the work and, if this is Python 3, do something less index-oriented like:
def swapPairs(array):
if len(array) < 2:
return array
a, b, *rest = array
return [b, a, *swapPairs(rest)]

How to modify a variable in a class function

So i got this function. It must not be changed!
class TestUnikati(unittest.TestCase):
def test_02_clean(self):
s = [5, 4, 1, 4, 4, 4, 4, 4, 3]
unique_array(s) #<-- calls the function
self.assertEqual(s, [5, 4, 1, 3])
Basically we test if the function clean() only returns a unique array. The variable s being the array.
This is my function that get's the messy array s and tries to return an array of no duplicate elements
def unique_array(s):
s=unique(s) #<-- this is a function that just returns a unique array
x=TestUnikati() #<-- I store the class in the x variable
[insert a way to push s to the "TestUnikati.test_02_clean.s"]
I tried many things. I've tried some experiments with globals() and locals() as well as many things with the x object variable but I don't seem to get it right.
I've tried to push it to the locals() of TestUnikati.test_02_clean.s with the x object. Is there a way to save it so the s in the class function will be over-ridden and the self.assertEqual(s, [5, 4, 1, 3]) will compare the 2 and pass it? Something like this:
x.test_02_clean.s=unique(s)
or
x.s=unique(s)
As others have stated, since test_02_clean() doesn't assign the results of its call of unique_array() to anything, it's expecting you to mutate the given list in place. Something like this:
def unique_array(s):
# Keep a set of all the items we've seen so far
seen = set()
# Index into list
i = 0
while i < len(s):
if s[i] in seen:
# Delete element from list if we've already seen it
del s[i]
else:
# Or else add it to our seen list and increment the index
seen.add(s[i])
i += 1
>>> s = [5, 4, 1, 4, 4, 4, 4, 4, 3]
>>> unique_array(s)
>>> s
[5, 4, 1, 3]
you must have to change your class variable to access globally like below:-
class TestUnikati(unittest.TestCase):
def test_02_clean(self):
self.s = [5, 4, 1, 4, 4, 4, 4, 4, 3]
unique(self.s) <-- calls the function
self.assertEqual(self.s, [5, 4, 1, 3])
and also to reassign it with shorted value you have to do like:-
self.s=unique(s)
You need a function unique() that changes the list in place, instead of returning a new list, e.g.
def unique(l):
count = {}
for entry in l:
count[entry] = count.get(entry, 0) + 1
for entry in l:
for _ in range(count[entry] - 1):
l.remove(entry)
This works in place:
a = [1, 1, 1, 3, 4, 2]
unique(a)
print(a)
>>> [1, 3, 4, 2]

Rotating values in a list [Python]

I understand this question has been asked before but I haven't seen any that answer it in a way without splitting the list.
say I have a list:
num = [1,2,3,4,5,6]
I want to create a function:
rotate(lst, x):
So that if I call rotate(num, 3) it will globally edit the list num. That way when I later call print(num) it will result in [4,5,6,1,2,3].
I understand that I could write the function something like:
rotate(lst, x):
return [lst[-x:] + lst[:-x]
But I need to do this function without a return statement, and without splitting the list. What I'm thinking would work would be to put the last value of the list into a variable: q = lst[-1] and then from there create a loop that runs x amount of times that continues to move the values towards the end of the list and replacing the 0th position with whatever is stored in q.
One more thing. If I call rotate(lst, -3) then instead of rotating to the "right" it would have to rotate to the "left".
I'm new to python and having trouble wrapping my mind around this concept of manipulating lists. Thank you everyone for your time and effort. I hope this problem was clear enough.
You can use slicing assignment to modify your current strategy to do what you want. You're already generating the rotated list correctly, just modify the list in place with lst[:] = ...
def rotate(lst, x):
lst[:] = lst[-x:] + lst[:-x]
Example in the interactive interpreter:
>>> l = [1, 2, 3, 4, 5, 6]
>>> def rotate(lst, x):
... lst[:] = lst[-x:] + lst[:-x]
...
>>> rotate(l, 2)
>>> l
[5, 6, 1, 2, 3, 4]
Now rotate it backwards:
>>> rotate(l, -2)
>>> l
[1, 2, 3, 4, 5, 6]
>>> rotate(l, -2)
>>> l
[3, 4, 5, 6, 1, 2]
See this answer on a different question: https://stackoverflow.com/a/10623383/3022310
Here is a solution using a double-ended queue.
As required, it modifies the list in place, neither uses return nor uses chunks of the list.
from collections import deque
def rotate(lst, x):
d = deque(lst)
d.rotate(x)
lst[:] = d
num = [1,2,3,4,5,6]
rotate(num,3)
print(num)
rotate(num,-3)
print(num)
produces
[4, 5, 6, 1, 2, 3]
[1, 2, 3, 4, 5, 6]
Please have a look at PMOTW's tutorial on deque
def rotate(lst, num):
copy = list(lst)
for (i, val) in enumerate(lst):
lst[i] = copy[i - num]
Try:
num = [1,2,3,4,5,6]
def rotate(lst,x):
copy = list(lst)
for i in range(len(lst)):
if x<0:
lst[i+x] = copy[i]
else:
lst[i] = copy[i-x]
rotate(num, 2)
print num
Here is a simple method using pop and insert on the list.
num = [1,2,3,4,5,6]
def rotate(lst, x):
if x >= 0:
for i in range(x):
lastNum = lst.pop(-1)
lst.insert(0, lastNum)
else:
for i in range(abs(x)):
firstNum = lst.pop(0)
lst.append(firstNum)
return
print num #[1, 2, 3, 4, 5, 6]
rotate(num, 2)
print num #[5, 6, 1, 2, 3, 4]
rotate(num, -2)
print num #[1, 2, 3, 4, 5, 6]
I believe this satisfies all requirements. The idea is from the Programming Pearls book(http://goo.gl/48yJPw). To rotate a list we can reverse it and then reverse sublists with the rotating index as pivot.
def rotate(num, rot):
if rot < 0:
rot = len(num) + rot
rot = rot - 1
num.reverse()
for i in range(rot/2 + 1):
num[i], num[rot-i] = num[rot-i], num[i]
for i in range(1, (len(num) - rot)/2):
num[rot+ i], num[len(num) - i] = num[len(num) - i], num[rot+ i]
#Testing...
num = range(1, 10)
rot = -1
print num
rotate(num, rot)
print num

Categories

Resources