Вот решение numpy
, основанное на некоторой линейной алгебре.
Первое преобразование B
в основу:
import numpy as np
A = [1, 5, 2, 4, 3]
B = [0, 2, 1]
b = np.eye(len(B))[B]
print(b)
#array([[1, 0, 0],
# [0, 0, 1],
# [0, 1, 0]])
Теперь мы можем пройти через каждый подмассив A
и спроецировать его в это пространство. Если результирующий вектор отсортирован, это означает, что подрешетка следовала за ранжированием.
for i in range(0, (len(A) - len(B))+1):
a = np.array(A[i:i+len(B)])
if (np.diff(a.dot(b))>0).all():
print(a)
#[1 5 2]
#[2 4 3]
Я не эксперт по пустякам, так что может быть способ оптимизировать это дальше и устранить цикл.
Обновление, вот более чистая версия:
def get_ranked_subarrays(A, B):
m = len(A)
n = len(B)
b = np.eye(n)[B]
a = np.array([A[i:i+n] for i in range(0, m - n+1)])
return a[(np.diff(a.dot(b))>0).all(1)].tolist()
A = [1, 5, 2, 4, 3]
B = [0, 2, 1]
get_ranked_subarrays(A, B)
#[[1, 5, 2], [2, 4, 3]]
Результаты производительности:
Ваше решение очень хорошо для маленьких n
, но решение numpy превосходит, когда размер A
становится большим:
Вот ваш код, который я превратил в функцию, которая возвращает нужные подмассивы (вместо печати):
def get_ranked_subarrays_op(A, B):
m = len(A)
n = len(B)
out = []
for i in range(m - n + 1):
current_subarray = A[i:i + n]
# we now do n - 1 comparisons to check whether the subarray is correctly ordered.
for B_index in range(n - 1):
if current_subarray[B[B_index]] > current_subarray[B[B_index + 1]]:
break
else:
out.append(current_subarray)
return out
Временные результаты для большого случайного числа A
:
array_size = 1000000
A = np.random.randint(low=0, high=10, size=array_size)
B = [0, 2, 1]
%%timeit
get_ranked_subarrays_op(A, B)
#1 loop, best of 3: 1.57 s per loop
%%timeit
get_ranked_subarrays(A, B)
#1 loop, best of 3: 890 ms per loop
Однако, если m
также становится большим, ваше решение будет немного лучше из-за короткого замыкания (вероятность короткого замыкания становится большой для больших m
). Вот временные результаты, которые мы позволили m
быть 100.
array_size = 1000000
basis_size = 100
A = np.random.randint(low=0, high=10, size=array_size)
B = range(basis_size)
np.random.shuffle(B)
%%timeit
get_ranked_subarrays_op(A, B)
#1 loop, best of 3: 1.9 s per loop
%%timeit
get_ranked_subarrays(A, B)
#1 loop, best of 3: 2.79 s per loop