I have a 3D matrix that I want to index. The indexes are selected in a GUI so they may be out of range. I want to set values in the matrix if an index is out of range. Right now I have a code that does it with loops that is something like this:
list=[]
for i in range():
if X,Y,Z out of range:
a=1000
list.append(a)
else:
a=array_3d[X,Y,Z]
list.append(a)
Obviously, this is a slow method when the list becomes a high length. I have a code that indexes a one dimensional list as I want.
'''
import numpy as np
class Set_Value(list):
def _get_item_with_default(self, index, default_value):
return super(Set_Value, self).__getitem__(index) if index >= 0 and index < len(self) else default_value
def __getitem__(self, index):
if isinstance(index, int):
return self._get_item_with_default(index, 1000)
elif isinstance(index, list):
return [self._get_item_with_default(elem, 1000) for elem in index]
A=np.array([100,200,300,400])
S=Set_Value(A)
X=[1,1,1,1,1,1,1,1,1,1]
Y=[1,1,1,-5,-5,-5,1,1,1,1]
print(S[X])
print(S[Y])
'''
OUTPUT:
[200, 200, 200, 200, 200, 200, 200, 200, 200, 200]
[200, 200, 200, 1000, 1000, 1000, 200, 200, 200, 200]
I'm struggling to convert this to 3D, ie
'''
import numpy as np
import random
Class TestC():
#stuff to solve problem
array3d=np.random.randint(0,1000,size=(50,50,50))
set_3d=TestC(array3d)
X=random.sample(range(-100, 100), 100)
Y=random.sample(range(-100, 100), 100)
Z=random.sample(range(-100, 100), 100)
print(set_3d[X,Y,Z])
'''
OUTPUT:
[value pulled from array3d, value pulled from array3d, set value to 1000 if out of range, set value to 1000 if out of range, ...]
At this point, I am not even sure if it will be faster, but I am just curious if it can be done, and I cannot get it to work.
CodePudding user response:
As hinted by hpaulj, np.clip
and np.where
are useful here; no need to create a custom class.
# Convert all the indices into NumPy arrays
x, y, z = np.array(X), np.array(Y), np.array(Z)
# Keep track of out-of-range indices
is_x_oor = (x < 0) | (x >= array3d.shape[0])
is_y_oor = (y < 0) | (y >= array3d.shape[1])
is_z_oor = (z < 0) | (z >= array3d.shape[2])
# Ensure the indices stay within range
x = x.clip(0, array3d.shape[0] - 1)
y = y.clip(0, array3d.shape[1] - 1)
z = z.clip(0, array3d.shape[2] - 1)
# Perform indexing but take the default value if any index is out of range
res = np.where(is_x_oor | is_y_oor | is_z_oor, 1000, array3d[x, y, z])
You can then convert the result to list with res.tolist()
.