0

I want to rotate k element in a list in python. For example, n = 7, k = 3, and the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].

Here is the statement I wrote. It seems to work in the command line.

nums = nums[k%len(nums):] + nums[:k%len(nums)]

But when I encapsulate it in a function like:

def rotate(nums, k):
    nums = nums[k%len(nums):] + nums[:k%len(nums)]
    return

I want to modify nums directly, but this function doesn't work.

I know that I can use a for loop like:

for i in range(k):
    nums.insert(0,nums.pop())

but I want to know why the previous method doesn't work?

Garrett Hyde
  • 5,409
  • 8
  • 49
  • 55
Gavin
  • 25
  • 3
  • 1
    You create a new list inside the function then don't return or assign anything as a result; why did you expect that to make changes outside the function? – jonrsharpe Dec 31 '15 at 00:16
  • `nums=...` sets the local variable `nums`, but does not change the actual original list `nums`. for the inverse problem see http://stackoverflow.com/questions/2322068/python-passing-list-as-argument – Sanjay Manohar Dec 31 '15 at 00:17
  • 1
    Side-note: Even fixed with slice assignment, this is incredibly inefficient if the `list` is of significant size (you make a complete copy of the `list`, then copy back into the original `list`); if rotating sequences is important in your use case, consider [using `collections.deque`](https://docs.python.org/3/library/collections.html#collections.deque) which can perform rotation much more efficiently, with direct support for [in-place rotation](https://docs.python.org/3/library/collections.html#collections.deque.rotate). – ShadowRanger Dec 31 '15 at 00:47

3 Answers3

2

What you want is a slice assignment:

nums[:] = nums[k%len(nums):] + nums[:k%len(nums)]

This mutates the list that was passed in, so the change is visible after the function returns. Assigning just to nums merely makes nums point to a different list inside the function; it doesn't affect the original list.

kindall
  • 178,883
  • 35
  • 278
  • 309
1

Are you sure you want to modify nums? You need not create a separate list even if you do not modify nums. One advantage of the following approach is that it will work with any sequence.

from itertools import islice
def rotate(lst, k):
    n = len(lst)
    start = n - (k % n)  #handle all ints
    for item in islice(lst, start, None):
        yield item
    for item in islice(lst, 0, start):
        yield item

If you insist on modifying nums as you say, you can still do so. E.g.,

nums = [x + 1 for x in range(7)]
nums[:] = rotate(nums,-10)
Alan
  • 9,410
  • 15
  • 20
0

The nums that is inside the function is only within that function. So you need to return it from that function. One way is like this (python 2.7 code, add parentheses to print if you use 3.x):

nums = [1, 2, 3, 4, 5, 6, 7]
k = 3


def rotate(nums, k):
    return nums[k%len(nums):] + nums[:k%len(nums)]

print 'Original', nums
nums = rotate(nums, k)
print 'Rotated', nums
oystein-hr
  • 551
  • 4
  • 9