尝试使用RcppArmadillo编写setdiff()函数会导致编译错误 我试图用C++编写一个C++中的R的StimeDeffice()函数的类比。我的方法相当粗糙: // [[Rcpp::export]] arma::uvec my_setdiff(arma::uvec x, arma::uvec y){ // Coefficientes of unsigned integer vector y form a subset of the coefficients of unsigned integer vector x. // Returns set difference between the coefficients of x and those of y int n2 = y.n_elem; uword q1; for (int j=0 ; j<n2 ; j++){ q1 = find(x==y[j]); x.shed_row(q1); } return x; } /[[Rcpp::export]] arma::uvec my_setdiff(arma::uvec x,arma::uvec y){ //无符号整数向量y的系数构成无符号整数向量x的系数的子集。 //返回x和y的系数之间的集差 int n2=y.n_元素; uwordq1; 对于(int j=0;j

尝试使用RcppArmadillo编写setdiff()函数会导致编译错误 我试图用C++编写一个C++中的R的StimeDeffice()函数的类比。我的方法相当粗糙: // [[Rcpp::export]] arma::uvec my_setdiff(arma::uvec x, arma::uvec y){ // Coefficientes of unsigned integer vector y form a subset of the coefficients of unsigned integer vector x. // Returns set difference between the coefficients of x and those of y int n2 = y.n_elem; uword q1; for (int j=0 ; j<n2 ; j++){ q1 = find(x==y[j]); x.shed_row(q1); } return x; } /[[Rcpp::export]] arma::uvec my_setdiff(arma::uvec x,arma::uvec y){ //无符号整数向量y的系数构成无符号整数向量x的系数的子集。 //返回x和y的系数之间的集差 int n2=y.n_元素; uwordq1; 对于(int j=0;j,c++,r,rcpp,armadillo,C++,R,Rcpp,Armadillo,问题在于,arma::find返回一个uvec,并且不知道如何进行到arma::uword的隐式转换,正如@mtall所指出的。您可以使用模板化的arma::conv_to::from()来帮助编译器函数。此外,我还包括了另一个版本的my_setdiff,它返回一个Rcpp::NumericVector,因为尽管第一个版本返回正确的值,但从技术上讲它是一个矩阵(即它有维度),我假设您希望它尽可能与R的setdiff兼容。这是通过使用R\NilValue和Rcpp::attr成员函数将返回向量的d

问题在于,
arma::find
返回一个
uvec
,并且不知道如何进行到
arma::uword
的隐式转换,正如@mtall所指出的。您可以使用模板化的
arma::conv_to::from()来帮助编译器
函数。此外,我还包括了另一个版本的
my_setdiff
,它返回一个
Rcpp::NumericVector
,因为尽管第一个版本返回正确的值,但从技术上讲它是一个
矩阵(即它有维度),我假设您希望它尽可能与R的
setdiff
兼容。这是通过使用
R\NilValue
Rcpp::attr
成员函数将返回向量的
dim
属性设置为
NULL
来实现的



如果使用非唯一元素传递向量,则以前的版本将抛出错误,例如

R> my_setdiff2(X,Y)

error: conv_to(): given object doesn't have exactly one element
为了解决这个问题并更紧密地反映R的
setdiff
,我们只需要使
x
y
独一无二。此外,我用
q1(0)
arma::conv_切换到::from
(其中
q1
现在是
uvec
,而不是
uword
),因为
uvec
只是
uword
s的一个向量,显式转换似乎有点不雅观。

我使用了STL,从arma::uvec来回转换

#include <RcppArmadillo.h>
#include <algorithm>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::uvec std_setdiff(arma::uvec& x, arma::uvec& y) {

  std::vector<int> a = arma::conv_to< std::vector<int> >::from(arma::sort(x));
  std::vector<int> b = arma::conv_to< std::vector<int> >::from(arma::sort(y));
  std::vector<int> out;

  std::set_difference(a.begin(), a.end(), b.begin(), b.end(),
                      std::inserter(out, out.end()));

  return arma::conv_to<arma::uvec>::from(out);
}
#包括
#包括
//[[Rcpp::depends(RcppArmadillo)]]
//[[Rcpp::导出]]
arma::uvec标准设置差异(arma::uvec&x,arma::uvec&y){
std::vector a=arma::conv_to::from(arma::sort(x));
std::vector b=arma::conv_to::from(arma::sort(y));
std::向量输出;
设置差异(a.开始(),a.结束(),b.开始(),b.结束(),
std::inserter(out,out.end());
将arma::conv_返回到::from(out);
}
编辑:我认为应该进行性能比较。当集合的相对大小顺序相反时,差异会变小

a <- sample.int(350)
b <- sample.int(150)

microbenchmark::microbenchmark(std_setdiff(a, b), arma_setdiff(a, b))

> Unit: microseconds
>                expr    min      lq     mean median     uq     max neval cld
>   std_setdiff(a, b) 11.548 14.7545 17.29930 17.107 19.245  36.779   100  a 
>  arma_setdiff(a, b) 60.727 65.0040 71.77804 66.714 72.702 138.133   100   b
a表达式最小lq平均uq最大neval cld
>标准设置差异(a,b)11.54814.754517.2993017.10719.24536.779100 a
>阿马努塞迪夫(a,b)60.727 65.0040 71.77804 66.714 72.702 138.133 100 b

提问者可能已经得到了答案。但是,以下模板版本可能更通用。这相当于Matlab中的函数

如果p和Q是两个集合,那么它们的差异由p-Q或Q-p给出。如果
p={1,2,3,4}
Q={4,5,6}
,p-Q表示p中不在Q中的元素。即,在上面的示例中p-Q={1,2,3}

/* setdiff(t1, t2) is similar to setdiff() function in MATLAB. It removes the common elements and
   gives the uncommon elements in the vectors t1 and t2. */


template <typename T>
T setdiff(T t1, T t2)
{
    int size_of_t1 = size(t1);
    int size_of_t2 = size(t2);

    T Intersection_Elements;
    uvec iA, iB;
    intersect(Intersection_Elements, iA, iB, t1, t2);

    for (int i = 0; i < size(iA); i++)
    {
        t1(iA(i)) = 0;
    }

    for (int i = 0; i < size(iB); i++)
    {
        t2(iB(i)) = 0;
    }

    T t1_t2_vec(size_of_t1 + size_of_t2);
    t1_t2_vec = join_vert(t1, t2);
    T DiffVec = nonzeros(t1_t2_vec);


    return DiffVec;
}
/*setdiff(t1,t2)类似于MATLAB中的setdiff()函数。它删除了常用元素和
给出向量t1和t2中的不常见元素*/
模板
T setdiff(T t1,T t2)
{
int size_of_t1=大小(t1);
int size_of_t2=大小(t2);
T交叉元素;
uvecia,iB;
相交(相交元素、iA、iB、t1、t2);
对于(int i=0;i

欢迎提出任何改进算法性能的建议。

shed_row()
可能不是
arma::uvec
的成员函数。行
q1=find(x==y[j])
是错误的。的输出总是,而不是uword。这不符合预期。例如,
arma_setdiff(10:13,4:5)
为我抛出了一个错误:
arma_setdiff(10:13,4:5)中的错误:Mat::operator():索引超出范围
@Johan Larsson fixed。
#include <RcppArmadillo.h>
#include <algorithm>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::uvec std_setdiff(arma::uvec& x, arma::uvec& y) {

  std::vector<int> a = arma::conv_to< std::vector<int> >::from(arma::sort(x));
  std::vector<int> b = arma::conv_to< std::vector<int> >::from(arma::sort(y));
  std::vector<int> out;

  std::set_difference(a.begin(), a.end(), b.begin(), b.end(),
                      std::inserter(out, out.end()));

  return arma::conv_to<arma::uvec>::from(out);
}
a <- sample.int(350)
b <- sample.int(150)

microbenchmark::microbenchmark(std_setdiff(a, b), arma_setdiff(a, b))

> Unit: microseconds
>                expr    min      lq     mean median     uq     max neval cld
>   std_setdiff(a, b) 11.548 14.7545 17.29930 17.107 19.245  36.779   100  a 
>  arma_setdiff(a, b) 60.727 65.0040 71.77804 66.714 72.702 138.133   100   b
/* setdiff(t1, t2) is similar to setdiff() function in MATLAB. It removes the common elements and
   gives the uncommon elements in the vectors t1 and t2. */


template <typename T>
T setdiff(T t1, T t2)
{
    int size_of_t1 = size(t1);
    int size_of_t2 = size(t2);

    T Intersection_Elements;
    uvec iA, iB;
    intersect(Intersection_Elements, iA, iB, t1, t2);

    for (int i = 0; i < size(iA); i++)
    {
        t1(iA(i)) = 0;
    }

    for (int i = 0; i < size(iB); i++)
    {
        t2(iB(i)) = 0;
    }

    T t1_t2_vec(size_of_t1 + size_of_t2);
    t1_t2_vec = join_vert(t1, t2);
    T DiffVec = nonzeros(t1_t2_vec);


    return DiffVec;
}