使用Rcpp erase函数删除向量零元素时出现遗漏问题求助
Rcpp删除向量零元素的异常问题与性能分析
问题代码与异常表现
我编写了一段Rcpp代码,意图通过erase(i)函数删除向量中的零元素:
#include <Rcpp.h> using namespace Rcpp; // [[Rcpp::export]] NumericVector erase_zero(NumericVector x) { for (int i = 0; i < x.size(); i++) { if (x[i] == 0) { x.erase(i); } } return x; }
但运行后出现异常输出,部分零元素未被正确删除:
> erase_zero(c(0,1,2,3,0)) [1] 1 2 3 > erase_zero(c(0,0,1,2,3,0,0)) [1] 0 1 2 3 0 > erase_zero(c(0,0,0,1,2,3,0,0,0)) [1] 0 1 2 3 0 > erase_zero(c(0,0,0,0,1,2,3,0,0,0,0)) [1] 0 0 1 2 3 0 0
问题原因
漏删零元素的核心原因是向量删除元素后的索引偏移:
- 执行
x.erase(i)时,向量长度会减1,原本位于i+1位置的元素会前移到i的位置 - 但循环的
i会继续递增,直接跳过了前移到i位置的零元素,导致连续的零无法被全部处理
举个例子,处理c(0,0,1...)时:
- i=0,删除第一个0,向量变为
c(0,1...) - i递增到1,此时访问的是元素1,完全跳过了现在位于i=0位置的第二个零,最终导致该零残留
性能测试结果
后续针对不同实现方案做了性能测试,结果如下:
> microbenchmark(erase_zero(s), erase_zero1(s), erase_zero_sugar(s)) Unit: microseconds expr min lq mean median uq max neval erase_zero(s) 19.311 21.2790 22.54262 22.181 22.8780 35.342 100 erase_zero1(s) 18.573 21.0945 21.95222 21.771 22.4680 36.490 100 erase_zero_sugar(s) 1.968 2.0910 2.57070 2.296 2.5215 24.887 100
其中erase_zero1是Roland提供的首个修正实现,另外ThomasIsCoding提出的R base方法,效率优于所有测试的Rcpp实现。
内容的提问来源于stack exchange,提问作者ann
相关产品推荐
相关产品推荐

