Вот один с array-assignment
+ masking
для положительных чисел -
def unionize_ndarrays(L, maxnum=None):
if maxnum is None:
maxnum = max([np.max(i) for i in L])+1
# for lists : max([max(i) for i in L])+1
id_ar = np.zeros(maxnum, dtype=bool)
for i in L:
id_ar[i] = True
return np.flatnonzero(id_ar)
Вычисление максимального числа maxnum
имеет заметное время выполнения и может стать узким местом даже для большого количества маленьких массивов. Так что, если это известно, кормление в этом случае очень поможет в этих сценариях ios.
Пробный прогон -
In [43]: a = np.array([0, 1, 3, 4, 3])
...: b = np.array([0, 10, 3, 1, 2, 1])
...: c = np.array([6, 3, 4, 2])
In [44]: np.unique(np.concatenate((a,b,c)))
Out[44]: array([ 0, 1, 2, 3, 4, 6, 10])
In [45]: unionize_ndarrays((a,b,c))
Out[45]: array([ 0, 1, 2, 3, 4, 6, 10])
Сравнительный анализ
1) Малогабаритные массивы -
In [106]: L = [np.random.randint(0,10,n) for n in np.random.randint(4,10,10000)]
In [107]: %timeit unionize_ndarrays(L, maxnum=10)
2.74 ms ± 207 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [108]: %timeit np.unique(np.concatenate((L)))
3.06 ms ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# Without maxnum fed
In [109]: %timeit unionize_ndarrays(L)
40.4 ms ± 542 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Если порядок не важен, мы также можем рассмотреть pandas.factorize
, если мы имеем дело с малогабаритными массивами -
In [76]: a = np.array([0, 1, 3, 4, 3])
...: b = np.array([0, 10, 3, 1, 2, 1])
...: c = np.array([6, 3, 4, 2])
In [77]: L = [a,b,c]
In [80]: import pandas as pd
In [81]: pd.factorize(np.concatenate(L))[1]
Out[81]: array([ 0, 1, 3, 4, 10, 2, 6])
Связанные тайминги -
In [82]: L = [np.random.randint(0,10,n) for n in np.random.randint(4,10,10000)]
In [84]: %timeit pd.factorize(np.concatenate(L))[1]
2.1 ms ± 13.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2) Массивы больших размеров (большие различия в размерах) -
Тайминги -
In [2]: L = [np.random.randint(0,1000,n) for n in np.random.randint(10,1000,10000)]
In [3]: %timeit unionize_ndarrays(L, maxnum=1000)
...: %timeit unionize_ndarrays(L)
...: %timeit np.unique(np.concatenate((L)))
14 ms ± 925 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
56.6 ms ± 641 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
242 ms ± 773 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
Таким образом, выбор одного из них будет зависеть от есть ли у нас априорная информация о максимальном числе и изменении размера.