Вы, конечно, можете векторизовать мясо вашего l oop, если векторизуете op
(python соглашается использовать snake_case). Например, учитывая ваш начальный массив,
A = np.array([[0, 2, 3],
[0,-3,-1],
[0, 4, 3]])
Начните с определения op
, которое работает на все сразу:
def op(x):
return np.stack((x[:, 0], -x[:, 2], x[:, 1] - x[:, 2]), axis=1)
Вы можете комбинировать массивы, сначала маскируя части, которые уже продублированы в A
. Использование @ подхода Untubu asvoid
в сочетании с in1d
.
dt = np.dtype((np.void, A.dtype.itemsize * A.shape[-1]))
def asvoid(arr):
arr = np.ascontiguousarray(arr)
if np.issubdtype(arr.dtype, np.floating):
arr += 0.
return arr.view(dt).squeeze()
Для построения массива ваш l oop может выглядеть примерно так:
while True:
B = op(A)
mask = np.in1d(asvoid(B), asvoid(A), invert=True)
if mask.any():
A = np.concatenate((A, B[mask]), axis=0)
else:
break
Когда вы закончите, у вас будет две перестановки строк: A
и op(A)
. Вы можете вычислить индекс сортировки от одного к другому, используя метод, подобный методу { ссылка }:
oa = np.argsort(asvoid(A), axis=0)
ob = np.argsort(asvoid(B), axis=0)
ib = np.empty_like(oa)
ib[ob] = np.arange(B.shape[0])
J = oa[ib]
Вы также можете наращивать J
постепенно, так как вы знаете, что каждый элемент A
на данной итерации уже имеет J
, тогда как приращение с предыдущей итерации (B
) может или не может быть. На самом деле, вам следует звонить op
только с постоянно уменьшающейся B
, если закрытие гарантировано. Единственная проблема заключается в том, что вам нужно будет поддерживать A
в отсортированном порядке (argsorted в порядке), так как вы добавляете элементы B
для облегчения поиска.