Вы можете использовать cumsum
и найти первый бул, сравнив результат с 1.
all_bools.cumsum(axis=1).cumsum(axis=1) == 1
array([[False, True, False],
[ True, False, False],
[False, False, True],
[False, False, False]])
Это также объясняет проблему, указанную @a_guest. Второй вызов cumsum
необходим, чтобы избежать совпадения всех значений False
между первым и вторым значением True
.
Если важна производительность, используйте argmax
и установите значения:
y = np.zeros_like(all_bools, dtype=bool)
idx = np.arange(len(x)), x.argmax(axis=1)
y[idx] = x[idx]
y
array([[False, True, False],
[ True, False, False],
[False, False, True],
[False, False, False]])
Сроки исполнения Perfplot
Я воспользуюсь этой возможностью, чтобы продемонстрировать perfplot
с некоторыми временными интервалами, так как приятно видеть, как наши решения варьируются в зависимости от входных данных разного размера.
import numpy as np
import perfplot
def cs1(x):
return x.cumsum(axis=1).cumsum(axis=1) == 1
def cs2(x):
y = np.zeros_like(x, dtype=bool)
idx = np.arange(len(x)), x.argmax(axis=1)
y[idx] = x[idx]
return y
def a_guest(x):
b = np.zeros_like(x, dtype=bool)
i = np.argmax(x, axis=1)
b[np.arange(i.size), i] = np.logical_or.reduce(x, axis=1)
return b
perfplot.show(
setup=lambda n: np.random.randint(0, 2, size=(n, n)).astype(bool),
kernels=[cs1, cs2, a_guest],
labels=['cs1', 'cs2', 'a_guest'],
n_range=[2**k for k in range(1, 8)],
xlabel='N'
)
Тенденция переносится на большее N. cumsum
очень дорого, хотя между моим вторым решением и @ a_guest's есть постоянная разница во времени.