求Matlab中快速查找数组A元素在唯一向量b中对应索引的方法
快速查找数组元素在唯一向量中的索引
嘿,针对你这个在大数组里快速查找唯一值索引的需求,我给你推荐几个高效的MATLAB方案,绝对能解决速度慢的问题:
方案1:用ismember直接获取索引(最推荐,一步到位)
MATLAB内置的ismember函数专门做这种成员匹配,而且底层是高度优化的,完全不需要自己写循环。因为你的b是唯一向量,刚好完美适配这个函数的索引输出:
[~, B] = ismember(A, b);
这里第一个返回值~我们直接忽略(它是一个和A同尺寸的逻辑矩阵,标记A的元素是否存在于b中),第二个返回值B就是你要的结果——A中每个元素在b对应的唯一索引。
这个方法的时间复杂度是O(M log N)(M是A的总元素数,N是b的长度),对比你之前嵌套循环的O(M*N),速度会提升几个数量级,而且完全不会有内存溢出的问题。用你给出的数据规模测试的话,应该能在0.1秒以内完成,比原来的5.5秒快几十倍。
方案2:排序+二分查找(适合数值型整数,速度再升级)
如果你的b还没排序,可以先对b排序,再用二分查找进一步提速:
% 先对b排序,同时记录原索引的映射关系 [sorted_b, idx_map] = sort(b); % 用ismember在有序数组中做二分查找,获取位置 [~, pos] = ismember(A, sorted_b); % 把位置映射回原b的索引 B = idx_map(pos);
因为ismember在面对有序数组时会自动使用二分查找,比无序数组的查找速度更快。如果你的元素都是整数,还可以用histcounts做离散化查找,速度会更极致:
[sorted_b, idx_map] = sort(b); % 生成每个元素的边界,确保每个b元素对应唯一区间 edges = [-inf; (sorted_b(1:end-1)+sorted_b(2:end))/2; inf]; % 用histcounts找到A元素所在的区间位置 [pos, ~] = histcounts(A, edges); % 映射回原索引 B = idx_map(pos);
为什么你之前的方法效率低?
我来帮你分析下之前几个方案慢的原因:
- 嵌套循环:每次
find(A(i,j)==b,1)都要遍历整个b数组,总操作次数是rows*columns*length(b)——按你的数据规模就是1e445e5=2e10次,完全是暴力遍历,速度必然慢。 - 遍历b的循环:
B(A==b(idx))=idx每次都要对整个A做逻辑比较,生成大尺寸的逻辑矩阵,不仅内存开销大,循环次数更是达到5e5次,比嵌套循环的4e4次多了一个数量级,所以反而更慢。 - bsxfun方案:
bsxfun(@eq,A(:,i),b)会生成一个rows×length(b)的巨大矩阵,按你的数据就是1e4*5e5=5e9个元素,直接超出内存限制,完全不可行。
内容的提问来源于stack exchange,提问作者Johannes




