You can use a sliding_window_view
and check if the flipped view is identical. This solution is fully vectorized (non-loopy) but creates one additional array with size (len(a)-n,n)
.
import numpy as np
a = np.array([2, 6, 3, 2, 4, 5, 4, 2, 4, 7, 8, 7, 1])
def pal(arr, n):
x = np.lib.stride_tricks.sliding_window_view(arr, n)
return np.where(~(x != np.fliplr(x)).any(1))[0]
Your test cases:
pal(a,3)
Output
array([4, 6, 9])
pal(a,5)
Output
array([3])
Micro-Benchmark
Runtime benchmarks for the loop solution against the vectorized solution on a google colab instance in a jupyter notebook.
Results
vectorized with 100000
100 loops, best of 5: 3.74 ms per loop
vectorized with 1000000
10 loops, best of 5: 34.9 ms per loop
vectorized with 10000000
1 loop, best of 5: 343 ms per loop
loop with 100000
10 loops, best of 5: 33.3 ms per loop
loop with 1000000
1 loop, best of 5: 346 ms per loop
loop with 10000000
1 loop, best of 5: 3.42 s per loop
Code for the benchmark
import random
import numpy as np
def pal_vec(arr, n):
x = np.lib.stride_tricks.sliding_window_view(arr, n)
return np.where(~(x != np.fliplr(x)).any(1))[0]
def pal_loop(n):
r = []
for i in range(len(s) - n):
a = s[i:i + n]
if a == a[::-1]:
r.append(i)
return r
#preparing the data
r = [5,6,7]
looparr = [[random.randint(1, 9) for _ in range(10**k)] for k in r]
nparr = [np.array(e) for e in looparr]
# benchmarking
for arr in nparr:
print(f'vectorized with {len(arr)}')
%timeit pal_vec(arr,3)
for s in looparr:
print(f'loop with {len(s)}')
%timeit pal_loop(3)