1

Consider the following operation and slicing applied to two numpy arrays:

In [1]: import numpy as np                                                                               

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

In [3]: b = np.array([5,6,7,8])                                                                          

In [4]: a[2:] = 0                                                                                       

In [5]: a = a[::2]                                                                                       

In [6]: b[2:] = 0                                                                                       

In [7]: b = b[::2]                                                                                       

In [8]: a                                                                                                
Out[8]: array([1, 0])

In [9]: b                                                                                                
Out[9]: array([5, 0])

I do not want to repeat the slicing code, for example, instead of lines [4]-[7] above, I wish to use something like

In [4]: for data in [a,b] : 
   ...:     data[2:] = 0
   ...:     data = data[::2] 

I understand that it does not work because the effect of data = data[::2] is to make data to point a new object, not to change the original objects. So the values of a and b are not sliced:

In [5]: a                                                                                                
Out[5]: array([1, 2, 0, 0])

In [6]: b                                                                                                
Out[6]: array([5, 6, 0, 0])

My question is:

How to slice a numpy array referenced by a variable?

In my real application, I an doing several operations in each array, and want to have them all in the same block inside the for.

bmello
  • 1,864
  • 3
  • 18
  • 23

4 Answers4

2

You can use map to map the slicing on all the variables

import numpy as np                                                                               
a = np.array([1,2,3,4])                                                                          
b = np.array([5,6,7,8])

def func(x):
    x[2:] = 0
    x = x[::2] 
    return x
[a,b] = list(map(func,[a,b]))
print(a,b)

Output:

[1 0] [5 0]
paradocslover
  • 2,932
  • 3
  • 18
  • 44
  • Thanks, but no. I should have mentioned that I do other operations in the arrays. I will correct the question to make it clearer. – bmello Jun 02 '20 at 14:43
  • Then just replace the `lambda` function with function that contains all the operations that you want to apply. – paradocslover Jun 02 '20 at 14:44
  • I may be wrong, but I think that lambda functions can describe every possible operation in an array. For example, how could it code the operation described in my question? – bmello Jun 02 '20 at 15:01
  • I have removed `lambda` and used a general function. You can add more operations in it if you want. – paradocslover Jun 02 '20 at 15:02
  • I had thought of a similar solution `[a,b] = [func(x) for x in [a,b]]`, but I don't like the repetition of the same list of arrays in two places. – bmello Jun 02 '20 at 15:03
  • Thanks @paradoxlover. I wonder if a simpler solution exists, without the need of defining a new function. – bmello Jun 02 '20 at 15:05
  • Well, time to put on the thinking cap. :wink: – paradocslover Jun 02 '20 at 15:07
  • You can directly unpack the generator, no need to assign into a list in the lhs.. so `a,b = map(func,[a,b])` – yatu Jun 02 '20 at 15:07
1

Sounds like you want a dictionary:

import numpy as np

arrs = {'a': np.array([1,2,3,4]), 'b': np.array([5,6,7,8])}
arrs = {k: v[::2] for k, v in arrs.items()}
print(arrs)

output:

{'a': array([1, 3]), 'b': array([5, 7])}
jfaccioni
  • 7,099
  • 1
  • 9
  • 25
0

You could use a list comprehension:

a,b = [arr[::2] for arr in [a,b]]
bug_spray
  • 1,445
  • 1
  • 9
  • 23
0

There may be some confusion over creating array objects and assigning values.

Let me illustrate:

Define two arrays:

In [5]: a=np.arange(1,5); b=np.arange(5,10)                                     

Make a list of those two arrays:

In [6]: alist = [a,b]                                                           

and a generic function that returns a new array (the fact that it's a view doesn't matter):

In [7]: def foo(i): 
   ...:     return i[2:] 
   ...:    

The function could be applied to the array referenced by a:

In [8]: foo(a)                                                                  
Out[8]: array([3, 4])

or to each of the arrays referenced by alist:

In [9]: [foo(i) for i in alist]                                                 
Out[9]: [array([3, 4]), array([7, 8, 9])]

those arrays could be unpacked to variables (new or old names):

In [10]: a,d = [foo(i) for i in alist]                                          
In [11]: a                                                                      
Out[11]: array([3, 4])          # the new sliced array
In [12]: b                                                                      
Out[12]: array([5, 6, 7, 8, 9])    # the original array
In [13]: d                                                                      
Out[13]: array([7, 8, 9])           # a slice of b

the original arrays are still present in alist. The fact that a has a new value does not change alist:

In [14]: alist                                                                  
Out[14]: [array([1, 2, 3, 4]), array([5, 6, 7, 8, 9])]

unpacked assignment via map does the same thing:

In [15]: d,e = map(foo, alist)                                                  
In [16]: d,e                                                                    
Out[16]: (array([3, 4]), array([7, 8, 9]))

Making a dictionary of the sliced arrays also works:

In [17]: {key: foo(value) for key, value in zip(['e','d'],alist)}               
Out[17]: {'e': array([3, 4]), 'd': array([7, 8, 9])}
hpaulj
  • 221,503
  • 14
  • 230
  • 353