Home > Net >  How to change part of numpy array without reshaping
How to change part of numpy array without reshaping

Time:12-15

I have the the following array

import numpy as np
import CustomClass

# Total = 24
height = 4
width  = 6
a = np.empty((height, width), dtype=object)

for row in range(self.height):
    for col in range(self.width):
        self.a[row, col] = CustomClass()

I would like to change the attribute for part of the array (filled with my custom class). For example, I would like to change 12 elements starting from element[0,0], then from row to row. Ideally, I would do something comparable to

change=11
for i in range(change):
   a[i].value=True

The result would be something like the following (0: unchanged, x: changed)

x x x x x x 
x x x x x 0
0 0 0 0 0 0
0 0 0 0 0 0

The problem with my array is that I first need to flatten it before I could do something like this. Or I should calculate how many columns and rows I before I can index the array itself. Is there a numpy function such that I can just iteratre over the array element by element (row by row).

I hope my explanation is clear?

CodePudding user response:

You can do this a couple of ways, but one approach would be to use np.unravel_index to get the two-dimensional indices that correspond to the flattened one-dimensional ones. I'll show you how to do this below.

First create your data:

from dataclasses import dataclass
import numpy as np

height = 4
width  = 6

@dataclass
class myClass:
    value: bool = False
        
data = np.asarray([myClass() for _ in range(height * width)])
data = data.reshape(height, width)

Now, make change an array of indices that you want to change, rather than the number of elements you want to change:

change = np.arange(11)

Determine the two-dimensional indices that correspond to those in change:

rows, columns = np.unravel_index(indices=change, shape=(height, width))

And then you can use these indices to iterate over the elements you want to change:

for element in data[rows, columns]:
    element.value = True

CodePudding user response:

You can use variable to count how many elements was changed and use break to exit loops

import numpy as np


height = 4
width  = 6
a = np.empty((height, width), dtype=object)
a[:] = '0'

count = 0

for row in range(height):
    for col in range(width):
        count  = 1
        a[row, col] = 'x'
        if count == 11:
            break
    if count == 11:
       break
    
print(a)        

Result:

[['x' 'x' 'x' 'x' 'x' 'x']
 ['x' 'x' 'x' 'x' 'x' '0']
 ['0' '0' '0' '0' '0' '0']
 ['0' '0' '0' '0' '0' '0']]

To make it simpler you can set count = 11 at start and later substract until you get 0.

This way you have to set 11 only in one place.

import numpy as np

height = 4
width  = 6
a = np.empty((height, width), dtype=object)
a[:] = '0'

count = 11

for row in range(height):
    for col in range(width):
        count -= 1
        a[row, col] = 'x'
        if count == 0:
            break
    if count == 0:
       break
    
print(a)        

EDIT:

You could also calculate how many full rows you have to change and how many elements you have to change in last row.

import numpy as np

height = 4
width  = 6
a = np.empty((height, width), dtype=object)
a[:] = '0'

count = 11

rows = count // width
rest = count % width    

a[:rows] = 'x'
a[rows,:rest] = 'x'

print(a)

But this will not work if you want to start in different place then [0,0]

  • Related