给定两个通用的numpy 1-d数组(无论如何都不保证值),我需要检查一个数组是否为另一个的子数组。
通过强制转换为字符串很容易且很短,但可能不是最有效的:
import numpy as np
def is_sub_arr(a1, a2):
return str(a2).strip('[]') in str(a1).strip('[]')
arr1 = np.array([9, 1, 3, 2, 7, 2, 7, 2, 8, 5])
arr2 = np.array([3, 2, 7, 2])
arr3 = np.array([1,3,7])
print(is_sub_arr(arr1,arr2)) # True
print(is_sub_arr(arr1,arr3)) # False
是否有一种有效的内置/本机numpy方法来做到这一点?
答案 0 :(得分:3)
编辑:您还可以使用Numba以更少的内存使处理速度更快(例如1000倍):
import numpy as np
import numba as nb
def is_sub_arr_np(a1, a2):
l1, = a1.shape
s1, = a1.strides
l2, = a2.shape
a1_win = np.lib.stride_tricks.as_strided(a1, (l1 - l2 + 1, l2), (s1, s1))
return np.any(np.all(a1_win == a2, axis=1))
@nb.jit(parallel=True)
def is_sub_arr_nb(a1, a2):
for i in nb.prange(len(a1) - len(a2) + 1):
for j in range(len(a2)):
if a1[i + j] != a2[j]:
break
else:
return True
return False
# Test
np.random.seed(0)
arr1 = np.random.randint(100, size=100_000)
arr2 = np.random.randint(100, size=1_000)
print(is_sub_arr_np(arr1, arr2))
# False
print(is_sub_arr_nb(arr1, arr2))
# False
# Now enforce a match at the end
arr1[-len(arr2):] = arr2
print(is_sub_arr_np(arr1, arr2))
# True
print(is_sub_arr_nb(arr1, arr2))
# True
# Timing
%timeit is_sub_arr_np(arr1, arr2)
# 99.4 ms ± 567 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit is_sub_arr_nb(arr1, arr2)
# 124 µs ± 863 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
不确定这是最有效的答案,但这是一种可能的解决方案:
import numpy as np
def is_sub_arr(a1, a2):
l1, = a1.shape
s1, = a1.strides
l2, = a2.shape
a1_win = np.lib.stride_tricks.as_strided(a1, (l1 - l2 + 1, l2), (s1, s1))
return np.any(np.all(a1_win == a2, axis=1))
arr1 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
arr2 = np.array([4, 5, 6])
arr3 = np.array([4, 5, 7])
print(is_sub_arr(arr1, arr2))
# True
print(is_sub_arr(arr1, arr3))
# False
答案 1 :(得分:2)
尽管已经有一个可以接受的答案,但我想提出我的快速而肮脏的解决方案:
const bcrypt = require('bcryptjs');
userSchema.pre('save', async function (next) {
console.log('just before saving')
const rounds = 10; // What you want number for round paasword
const hash = await bcrypt.hash(this.password, rounds);
this.password = hash;
next()
})
这当然仅在数组使用连续内存的情况下有效,因此完整功能为:
memoryview(arr2).tobytes() in memoryview(arr1).tobytes()
这比OP中短而简单的字符串转换要快得多,也比不同阵列大小的(非数字加速)stride和cut解决方案要快:
def is_sub_arr_mem(a, sub):
if a.flags['FORC'] and sub.flags['FORC']:
return memoryview(sub).tobytes() in memoryview(a).tobytes()
return None
(n1和n2分别是arr1和arr2的大小)
答案 2 :(得分:1)
您可以尝试以下操作:
import numpy as np
arr1 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 5, 6, 20, 67, -1])
arr2 = np.array([4, 5, 6])
arr3 = np.array([4, 5, 7])
def is_sub_arr(original, sub):
first_match = np.where(original == sub[0])
if len(first_match) == 0:
print("no matches")
return
else:
for match in first_match[0]:
cut_original = original[match:match + len(sub)]
if np.all(cut_original == sub):
print("Got a match at index ", match)
else:
print("no match")
return
is_sub_arr(arr1, arr2)
is_sub_arr(arr1, arr3)
首先,我们检查子数组的第一个元素是否在原始数组中,并使用np.where
获取其索引。然后,对于每次匹配,我们都将剪切从该索引处开始到该索引处结束的原始数组,再加上子数组的长度,并检查是否与子数组本身匹配。