Reemplazar elementos en matriz con instancias de clase

Esto es similar a esto, así que, por favor, léalo primero para entender lo que estoy tratando de hacer.

Ahora, quiero hacer el reemplazo cuando tenga instancias de clase. Algo como:

import numpy as np class B(): def __init__(self, a,b): self.a = a self.b = b arr = np.array([ [1,2,3,4,5],[6,7,8,9,10] ]) b1 = np.array([B(100,'a'), B(11,'b'), B(300,'c'), B(33,'d')]) b2 = np.array([B(45,'a'), B(65,'b'), B(77,'c'), B(88,'d')]) # My d array will be like that and I will have to # run 3 loops as below . I can't change that d = np.array([[b1],[b2]],dtype=object) # Replace the elements for i in d: for y in i: for idx,el in enumerate(y): #y[idx].a = arr.reshape(-1,5) # 5 is the size of every sublength of arr #print(y[idx].a) pass # Show the updated values for i in d: for y in i: for idx,x in enumerate(y): print(y[idx].a) 

No puedo usar b = arr.reshape(-1, a.size) porque esto debe ejecutarse fuera de los bucles. Pero, como dije, la matriz b será el valor y[idx].value , así que no puedo simplemente colóquelo en el tercer ciclo porque obtendré resultados incorrectos, y tampoco puedo ubicarlo fuera del tercer ciclo porque no tendré acceso a la parte de value de la instancia de clase.

Quiero que mi resultado sea:

 b1 = np.array([B(1,'a'), B(2,'b'), B(3,'c'), B(4,'d'), B(5,'d')]) b2 = np.array([B(6,'a'), B(7,'b'), B(8,'c'), B(9,'d'), B(10,'d')]) 

Por lo tanto, quiero llenar solo a parte, por ejemplo, de las instancias de la clase B. Y tenga en cuenta que, como antes (en la pregunta anterior), la B se expande para contener los 5 valores de arr .

En pocas palabras, verifique la longitud de cada lista secundaria de arr (que ahora es 5) y actualice los valores de d consecuencia. Por lo tanto, si b1 y b2 tienen 4 valores, deben convertirse en 5 valores (los primeros 5 valores de arr y los siguientes 5 valores de arr ).

Así que agrego

 print(d.shape) print(d) 

y obten

 2249:~/mypy$ python3 stack42283851.py (2, 1, 4) [[[<__main__.B object at 0xb71d760c> <__main__.B object at 0xb71d7aac> <__main__.B object at 0xb71d7acc> <__main__.B object at 0xb71e5cec>]] [[<__main__.B object at 0xb391718c> <__main__.B object at 0xb39171ac> <__main__.B object at 0xb39171cc> <__main__.B object at 0xb39171ec>]]] 

añadiendo un __repr__ a B obtengo

 1231:~/mypy$ python3 stack42283851.py (2, 1, 4) [[[B(100, a) B(11, b) B(300, c) B(33, d)]] [[B(45, a) B(65, b) B(77, c) B(88, d)]]] 

Añadiendo

 import itertools for a,b in itertools.zip_longest(arr[0,:],b1): print(a,b) 

produce

 1 B(100, a) 2 B(11, b) 3 B(300, c) 4 B(33, d) 5 None 

Cambiando eso a

 newlist = [] for a,b in itertools.zip_longest(arr[0,:],b1): if b is not None: new_b = B(a, bb) last_b = b else: new_b = B(a, last_b.b) newlist.append(new_b) print(np.array(newlist)) 

produce

 [B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)] 

Asigne eso a b1 , y repita para a[1,:] y b2 .

Para ser un poco más limpio, podría escribir ese código new_b como una función, y reescribir el bucle como una lista de comprensión.

Sí, podría modificar b en su lugar, por ejemplo

 ba = a 

pero como necesito crear un nuevo objeto B para reemplazar el None , ¿por qué molestarse? No puedo agregar el nuevo objeto B a la matriz b1 original. Por lo tanto, es más sencillo crear una nueva matriz a través de una lista.


Puedo hacer un cambio in situ de d y b1 con:

 def replace(a,b): ba = a f = np.frompyfunc(replace, 2, 1) f(arr[:,None,:4], d) # produces array of None; ignore print(d) print(b1) [[[B(1, a) B(2, b) B(3, c) B(4, d)]] # chgd d [[B(6, a) B(7, b) B(8, c) B(9, d)]]] [B(1, a) B(2, b) B(3, c) B(4, d)] # chgd b1 

Solo estoy usando frompyfunc como una forma de transmisión perezosa de mans mans para hacer arr contra todos los elementos. Tenga en cuenta que tengo que cambiar arr para que coincida con d forma. Además esto no añade ningún nuevo B() . Obviamente no puedes hacer eso en el lugar.


Mi B es

 class B(): def __init__(self, a,b): self.a = a self.b = b def __repr__(self): return 'B(%s, %s)'%(self.a, self.b) 

Jugando con frompyfunc poco más:

 getB_b = np.frompyfunc(lambda x: xb, 1,1) # fetch b attributes print(getB_b(d)) #[[['a' 'b' 'c' 'd']] # # [['a' 'b' 'c' 'd']]] mkB = np.frompyfunc(B, 2,1) # build array of B() with broadcasting print(mkB(arr, ['a','b','c','d','e'])) # [[B(1, a) B(2, b) B(3, c) B(4, d) B(5, e)] # [B(6, a) B(7, b) B(8, c) B(9, d) B(10, e)]] print(mkB(arr[:,:4], getB_b(d[:,0,:]))) # [[B(1, a) B(2, b) B(3, c) B(4, d)] # [B(6, a) B(7, b) B(8, c) B(9, d)]] 

editar para comentarios

 arr1 = np.array([ [1,2],[6,7] ]) newlist = [] for a,b in itertools.zip_longest(arr1[0,:],b1): if b is not None: new_b = B(a, bb) last_b = b else: new_b = B(a, last_b.b) newlist.append(new_b) print(np.array(newlist)) 

produce

 [B(1, a) B(2, b) B(None, c) B(None, d)] 

Cuando arr es más corto, a será None (en lugar de b ); así que tenemos que probar para eso

 def foo(arr,bn): newlist = [] for a,b in itertools.zip_longest(arr,bn): print(a,b) if a is None: pass else: if b is not None: new_b = B(a, bb) last_b = b else: new_b = B(a, last_b.b) newlist.append(new_b) return newlist print(np.array(foo(arr1[0,:],b1))) # arr1 shorter print(np.array(foo(arr[0,:], b2))) # arr longer 

pruebas:

 1 B(1, a) 2 B(2, b) None B(3, c) None B(4, d) [B(1, a) B(2, b)] 1 B(6, a) 2 B(7, b) 3 B(8, c) 4 B(9, d) 5 None [B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)] 

Nada especial o mágico; Sólo es una cuestión asegurarme de que obtengo las pruebas if y sangría correctas.

Haz el bloque de reemplazo como este. También tenga en cuenta que esto supone que su arr será estrictamente en múltiplos de 5 y que habrá tantos bloques como b1, b2, etc., ya que hay bloques en arr como se indica en el ejemplo.

 for i,b_arr in enumerate(d): temp_arr = [] for j in range(5): if j