HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Shift elements left by n indices in a list

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
shiftleftindiceselementslist

Problem

For the following question, the function

• should mutate the original list

• should NOT create any new lists

• should NOT return anything

Functions that do not create new lists are said to be ”in place.” Such functions are often desirable because they do not require extra memory to operate.

Define shift_left, a function that takes a list and shifts each element in the list to the left by n indices. If elements start ”falling off” on the left, they are placed back on the right. NOTE: you may assume that n is a non-negative integer.

def shift_left(lst, n):
"""Shifts the elements of lst over by n indices.
>>> lst = [1, 2, 3, 4, 5]
>>> shift_left(lst, 2)
>>> lst
[3, 4, 5, 1, 2]
"""


Below is the solution:

def shift_left(lst, n):
    """Shifts the lst over by n indices
    
    >>> lst = [1, 2, 3, 4, 5]
    >>> shift_left(lst, 2)
    >>> lst
    [3, 4, 5, 1, 2]
    """
    assert (n > 0), "n should be non-negative integer"
    def shift(ntimes):
        if ntimes == 0:
            return
        else:
            temp = lst[0]
            for index in range(len(lst) - 1):
                lst[index] = lst[index + 1]            
            lst[index + 1] = temp
            return shift(ntimes-1)
    return shift(n)


I have yet to learn about raising exceptions in Python.

Can this code be more elegant by following a recursive approach? As of now, space (stack frame) usage can be considered secondary.

Solution

Some suggestions:

-
The assignment says “ you may assume that n is a non-negative integer”, but the condition you check is “n > 0”. Since n = 0 is non-negative (and corresponds to no mutation of the list), you should handle that as well.

-
An assert should only really be used to check that the program isn’t in an impossible situation. It would be preferable to use exceptions, and it’s very simple to do so:

if n < 0:
    raise ValueError("Input %d is not a non-negative integer" % n)


(Alternatively, you could implement negative indices as right-shifting, but I’ll leave that for now.)

-
You can condense the for loop in shift with a list slice: the following code achieves the same effect:

lst[:-1] = lst[1:]


Everything except the last element in lst is assigned to the element one to its left in the original list.

You can extend this list slicing to do away with the temp variable (which is probably a bit more memory efficient), and do the list slicing in a single line. Shifting one position to the left is achieved with the line

lst[:] = lst[1:] + [lst[0]]


-
At that point, the shift() function is almost so simple that you can do away with it entirely, and recurse only on the shift_left() function. Here’s what I reduced it to:

if n == 0:
    return
else:
    lst[:] = lst[1:] + [lst[0]]
    shift_left(lst, n-1)

Code Snippets

if n < 0:
    raise ValueError("Input %d is not a non-negative integer" % n)
lst[:-1] = lst[1:]
lst[:] = lst[1:] + [lst[0]]
if n == 0:
    return
else:
    lst[:] = lst[1:] + [lst[0]]
    shift_left(lst, n-1)

Context

StackExchange Code Review Q#88684, answer score: 7

Revisions (0)

No revisions yet.