1

So the question is pretty strange. I wrote an algorithm to move contents of any list (array) by a given number of digits to the left.

DIGS = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

# move functions
def move(arr):
    this = arr
    first = this[0]
    for b in range(len(this) - 1):
        this[b] = this[b + 1]
    this[-1] = first
    return this

def move_with_step(arr, step):
    this_arr = arr
    for a in range(step):
        this_arr = move(arr)
    return this_arr

And, obviously, when typing print(move_with_step(DIGS, 5) will give us the same DIGS array but twisted. It will be something like [ 5, 6, 7... 3, 4 ]. You get the idea. And in this case it works. BUT...

The problem is: if I'd put this same call into the for loop like below or just one after another, it will give me wrong results which is kinda strange because it should'n modify DIGS itself and why is that happening IDK.

So this code

for a in range(1, 6):
    print(move_with_step(DIGS, a))

Returns this

[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
[6, 7, 8, 9, 0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]

in the console. Which is crazy and totally wrong. Why is that?

halfer
  • 19,824
  • 17
  • 99
  • 186

2 Answers2

3

The problem is that DIGS changes at each loop. So when you do:

for a in range(1, 6):
    print(move_with_step(DIGS, a))

At the end of the first loop DIGS=[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]. So at the second loop, it will start with DIGS already changed.

One simple solution, as stated by @depperm in the comments, is to pass a copy of the list:

for a in range(1, 6):
    print(move_with_step(DIGS[:], a))

Output:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[2, 3, 4, 5, 6, 7, 8, 9, 0, 1]
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
[4, 5, 6, 7, 8, 9, 0, 1, 2, 3]
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
Carles Mitjans
  • 4,786
  • 3
  • 19
  • 38
  • 1
    I'd argue that using `.copy()` instead of `[:]` would be more idiomatic and make your intent clearer. – Christian Dean Dec 29 '16 at 14:56
  • Or just `list(DIGS)`. That might be easier to understand. – Carles Mitjans Dec 29 '16 at 14:58
  • @leaf: `DIGS.copy()` is more idiomatic, but it should be mentioned it's only available from 3.3 onward (as OP did not specify the Python version used) – UnholySheep Dec 29 '16 at 15:03
  • @UnholySheep No, the OP did not say his Python version, but I can assume it is Python 3.x because [he is using print as a function and not a statement](https://docs.python.org/3/whatsnew/3.0.html#print-is-a-function). – Christian Dean Dec 29 '16 at 15:12
0

You should create a copy of the DIGS list in order to keep the original values. Then, pass a proper copy to the function and it should function fine.

Have a look at How to clone or copy a list?

Community
  • 1
  • 1
Guido
  • 6,182
  • 1
  • 29
  • 50
  • This is wrong, it has nothing to do with deep or shallow copies (both would work in this case as it is a list of integers). The parameter passed is a reference to a list, there is no copying. – UnholySheep Dec 29 '16 at 14:56
  • @UnholySheep I removed the deep/shallow part, now this should be correct – Guido Dec 29 '16 at 15:10