【发布时间】:2020-01-13 04:56:42
【问题描述】:
我注意到来自 Rcpp 的独特功能对结果进行排序
evalCpp("unique(IntegerVector::create(6,6,1,5,5,1))")
[1] 6 5 1
unique(c(6,6,1,5,5,1))
[1] 6 1 5
有没有办法避免这种情况? 感谢您的帮助
【问题讨论】:
我注意到来自 Rcpp 的独特功能对结果进行排序
evalCpp("unique(IntegerVector::create(6,6,1,5,5,1))")
[1] 6 5 1
unique(c(6,6,1,5,5,1))
[1] 6 1 5
有没有办法避免这种情况? 感谢您的帮助
【问题讨论】:
如果您查看(短)源文件,您会发现它使用了一个内部类IndexHash。我怀疑这是默认排序的。
如果原始订单是最重要的,我想您可以为自己编写一个新的便利包装器。不可能这么难:冒着浪费几个字节内存的风险,分配一个临时逻辑向量,使用标准哈希图并遍历传入的向量。对于每个值,询问 hashmap 是否已经看到这个值,存储布尔答案。然后用它来索引原始向量。
这甚至可能在某处实现。另请查看 Armadillo 和 Eigen 的实用函数。
【讨论】:
这可能对某人有所帮助 - 仅适用于已排序的向量。
template <int ITYPE>
Rcpp::Vector<ITYPE> unique(Rcpp::Vector<ITYPE> x) {
int n = x.size();
if (n == 1) return(x);
Rcpp::Vector<ITYPE> res;
res.push_back(x(0));
for (int i = 1; i < n; i++) {
if (x[i] != x(i - 1)) {
res.push_back(x(i));
}
}
return res;
}
【讨论】:
这就是我实现它的方式,以及我想出它时试图解决的issue(使用this answer,它还显示了各种其他解决方案和基准)。
template < typename T, int RTYPE >
inline SEXP sexp_unique( Rcpp::Vector< RTYPE > x ) {
std::set< T > seen;
auto newEnd = std::remove_if( x.begin(), x.end(), [&seen]( const T value ) {
if ( seen.find( value ) != std::end( seen ) ) {
return true;
}
seen.insert( value );
return false;
});
x.erase( newEnd, x.end() );
return x;
}
// returns unique values in their original input order
inline SEXP get_sexp_unique( SEXP s ) {
SEXP s2 = Rcpp::clone( s );
switch( TYPEOF( s2 ) ) {
case LGLSXP: {
return sexp_unique< bool, LGLSXP >( s2 );
}
case REALSXP: {
return sexp_unique< double, REALSXP >( s2 );
}
case INTSXP: {
return sexp_unique< int, INTSXP >( s2 );
}
case STRSXP: {
return sexp_unique< char* , STRSXP >( s2 );
}
default: Rcpp::stop("unknown vector type");
}
return 0;
}
【讨论】: