1

I am trying to left rotate an array in python3. The code that I am using is:

def rotLeft(a, d):
    b = a
    lengthOfArray = len(a)
    shift = d

    for i in range (0,lengthOfArray):
        print(a)
        newLocation = (i + (lengthOfArray - shift)) % lengthOfArray
        b[newLocation] = a[i]

    return b

if __name__ == '__main__':

    nd = input().split()

    n = int(nd[0])

    d = int(nd[1])

    a = list(map(int, input().rstrip().split()))

    result = rotLeft(a, d)

    print(result)

It takes three inputs from the user which are the length of the array of the elements, the number of rotations to perform and the array itself. But, instead of the elements rotating, the array is getting filled with the first element in the same position. For example:

Inputs:

5 4
12 76 1 09 13

Output:

[12, 12, 12, 12, 12]

What is wrong with my algorithm and how can I fix it?

Ajay Singh
  • 732
  • 1
  • 7
  • 16
  • 3
    Possible duplicate of [Left Rotation on an Array](https://stackoverflow.com/questions/49462195/left-rotation-on-an-array) – razdi May 09 '19 at 10:16
  • 3
    `b = a` doesn't make a *copy* of the list. `a` and `b` are references to the same list. Thus, `b[newLocation] = a[i]` has the same result as, `a[newLocation] = a[i]` See, [How to clone or copy a list](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – lurker May 09 '19 at 10:18

5 Answers5

3

There is an error in your first line of your rotate method:

A simple assignment like b = a doesn't create a real copy of a list as one would expect it to. Instead both variables just point to the same list in memory. So if you change something in a the changes will also be reflected in b and vice versa.

To create a new copy of that array use:

b = a[:]

For more possibilities to copy an array, check this out: How to clone or copy a list?

winklerrr
  • 13,026
  • 8
  • 71
  • 88
2

Use the copy module to effectively copy a list without sharing the same address in memory.

import copy

b = copy.copy(a)

instead of

b = a

For details about why those two are different, see https://docs.python.org/2/library/copy.html.

Also, maybe consider just using list comprehension :

def rotLeft(a, d):
    lengthOfArray = len(a)
    shift = d
    return [a[i + shift - lengthOfArray] for i in range(lengthOfArray)]
Mohammed H
  • 6,880
  • 16
  • 81
  • 127
Ashargin
  • 498
  • 4
  • 11
1

Your algorithm is perfectly fine, the only issue is b=a makes b also point to a, but what you want is to take a copy of a, achieved by doing list slicing b = a[:], and then the code works perfectly fine.

def rotLeft(a, d):
    #Take copy of a and assign to b
    b = a[:]
    lengthOfArray = len(a)
    shift = d

    for i in range (0,lengthOfArray):
        newLocation = (i + (lengthOfArray - shift)) % lengthOfArray
        b[newLocation] = a[i]

    return b

print(rotLeft([12, 76, 1, 9, 13], 4))

The output will be

[13, 12, 76, 1, 9]
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
0

You are making some complex stuff. Make it simple. You wanted to rotate left by "n" positions , so for example length-of-array(l) =5 ,rotate(n)=3. Take first 3 elements from start and add at the back of array.

If n > length-of-array(l) then take first "n - [ n mod l ]" elements and add at black of array.

0

I didn't do it by slicing. Here is my implementation, although it is not that efficient.

  1. for loop to run the function d times: kind of like recursion

  2. while loop to generate the list and save state of each iteration

    def rotLeft(a, d):
    
       for _ in range(d):
          i=0
          list1=[]
          while i<len(a):
              if i==len(a)-1:
                 list1.append(a[0])
              else:
                 list1.append(a[i+1])    
              i+=1
          a=list1.copy()   
       return a