Austin
Austin

Reputation: 21

Updating numpy array in loop

I am getting some strange results from the following but am relatively new to python so may be messing something up. The following:

import numpy as np

a = np.array([1,2,3,4])
print(a)

old_a = a

for x in range(0,1):
   new_a = old_a
   new_a[0] = old_a[1]
   new_a[1] = old_a[2]
   new_a[2] = old_a[3]
   new_a[3] = old_a[0]
   print(new_a)

[1 2 3 4]
[2 3 4 2]

I would have expected the second array to be [2 3 4 1].

However, if I create a new array as with the "clean" def below, it seems to work

def clean(b_in):
   out = np.zeros(4)
   for x in range(0,4):
       out[x] = b_in[x]
   return out

b = np.array([1,2,3,4])
print(b)

new_b = b

for x in range(0,1):
   old_b = clean(new_b)
   new_b[0] = old_b[1]
   new_b[1] = old_b[2]
   new_b[2] = old_b[3]
   new_b[3] = old_b[0]
   print(new_b) 

[1 2 3 4]
[2 3 4 1]

What am I missing and how do I avoid the clean def?

Thanks

**** Updated question below ****

Thanks for the responses. So, notwithstanding the response regarding the roll function below, is this the best way to do achieve the same as the roll function?

import numpy as np

a = np.array([1,2,3,4])
print(a)

old_a = a

for x in range(0,10):
   new_a = old_a.copy()
   new_a[0] = old_a[1]
   new_a[1] = old_a[2]
   new_a[2] = old_a[3]
   new_a[3] = old_a[0]
   old_a = new_a.copy()
   print(new_a)

Thanks again

EDIT

This is what I settled on:

import numpy as np

a = np.array([1,2,3,4])
print(a)

old_a = a
new_a = np.zeros_like(old_a)

for x in range(0,10):
    new_a[0] = old_a[1]
    new_a[1] = old_a[2]
    new_a[2] = old_a[3]
    new_a[3] = old_a[0]
    old_a = new_a.copy()
    print(new_a)

[1 2 3 4]
[2 3 4 1]
[3 4 1 2]
[4 1 2 3]
[1 2 3 4]
[2 3 4 1]
[3 4 1 2]
[4 1 2 3]
[1 2 3 4]
[2 3 4 1]
[3 4 1 2]

Thank you all!

Upvotes: 1

Views: 15251

Answers (3)

Merlin
Merlin

Reputation: 25639

See if this helps you understand what you are doing:

import numpy as np

a = np.array([1,2,3,4])
print(a)

old_a = a

for x in range(0,1):
    new_a = old_a
    new_a[0] = old_a[1]
    print  new_a
    new_a[1] = old_a[2]
    print  new_a
    new_a[2] = old_a[3]
    print  new_a
    new_a[3] = old_a[0]
    print(new_a)

[1 2 3 4]
[2 2 3 4]
[2 3 3 4]
[2 3 4 4]
[2 3 4 2]

So when you do this new_a[3] = old_a[0], position O is already "2". Below gives you what you expected.

for x in range(0,1):
    new_a = old_a.copy()
    new_a[0] = old_a[1]
    print  new_a
    new_a[1] = old_a[2]
    print  new_a
    new_a[2] = old_a[3]
    print  new_a
    new_a[3] = old_a[0]
    print(new_a)

[1 2 3 4]
[2 2 3 4]
[2 3 3 4]
[2 3 4 4]
[2 3 4 1]

The fastest way to do this is 'fancy' indexing :

a     = np.array([1,2,3,4])
new_a = a[np.array([1,2,3,0])]
print new_a

array([2, 3, 4, 1])

Upvotes: 0

Ashish Ranjan
Ashish Ranjan

Reputation: 5543

When you're changing the values of new_a you're also changing the values of old_a as you're doing shallow copy and not deepcopy by assigning new_a = old_a:

new_a[0] = old_a[1]
new_a[1] = old_a[2]
new_a[2] = old_a[3]
#old_a[0] is already old_a[1], as you reassigned it on line #1
new_a[3] = old_a[0] 

Here's the difference between shallow and deepcopy as in Python Docs:

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

You can avoid your clean def by using deepcopy or copy() in case of numpy array:

import numpy as np
#from copy import deepcopy #for python lists
a = np.array([1,2,3,4])
print(a)
old_a = a
for x in range(0,1):
   #new_a = deepcopy(old_a) #for python lists
   new_a = old_a.copy() # for numpy array
   new_a[0] = old_a[1]
   new_a[1] = old_a[2]
   new_a[2] = old_a[3]
   new_a[3] = old_a[0]
   print(new_a)

EDIT

After your updated question, looks like you want to update the old_a itself, so no need to copy it to new array, you can simply achieve what you're trying to do like this:

import numpy as np
a = np.array([1,2,3,4])
print(a)
old_a = a
for x in range(0,1):
   old_a[0], old_a[1], old_a[2], old_a[3] = old_a[1], old_a[2], old_a[3], old_a[0]
   print(old_a)

Upvotes: 0

Chiel
Chiel

Reputation: 6194

Even though this answer is not answering your question, for your specific case there is a much simpler solution, if shifting the elements by one is what you are searching for. It avoids the complexity in which you are getting stuck, and it simplifies things.

import numpy as np

a = np.array([1,2,3,4])
b = np.roll(a, -1)
print(a, b)

Output

[1 2 3 4] [2 3 4 1]

Upvotes: 2

Related Questions