在Rcpp中测试价值身份

Rya*_*ell 2 r rcpp

我是一个相对绿色的Rcpp用户,我不确定如何测试两个值是否相同.

例如,以下函数用于测试值是否包含在列表中,但是对于简单测试用例返回不正确的结果

#include <Rcpp.h>
using namespace Rcpp;    

// [[Rcpp::export]]
LogicalVector is_member (SEXP val, List coll) {    

    int coll_len = coll.size();    

    if (coll_len == 0) {
        return LogicalVector::create();
    } else {    

        Function identical("identical");    

        for (int ith = 0; ith < coll_len; ++ith) {    

            SEXP elem = coll[ith];    

            if (identical(val, elem)) {
                return true;
            }
        }    

        return false;
    }
}

is_member(1L, list(1L))
# FALSE
is_member(NaN, list(NaN, NaN))
# False
Run Code Online (Sandbox Code Playgroud)

为什么会这样,以及如何使用相同的极端情况和基本功能"相同"的持久性来测试身份?我找不到任何Rcpp糖用于此目的,但是如果我找不到直接解决方案,我怀疑无序集或者可能使用唯一函数来测试身份.

如果我的C++是非惯用的/危险的,我也会感激反馈,如果我一直含糊不清,请在下面留言,我会修改我的问题.

谢谢

Kev*_*hey 5

呵呵,看来你无意中发现了一个小错误-我们不转换boolLogicalVector以预期的方式.

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
LogicalVector return_true() {
  return true;
}

/*** R
return_true()
*/
Run Code Online (Sandbox Code Playgroud)

> return_true()
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

那么也许LogicalVector::create(true)现在回来?

代码中的另一个大问题:identical返回a SEXP,而不是bool!您希望bool明确地获得结果:

Shield<SEXP> result(identical(val, elem));
if (LOGICAL(result)[0]) { ... }
Run Code Online (Sandbox Code Playgroud)

虽然直接分配结果bool应该可行,但似乎可能没有.回电话时还有像这样的陷阱.

也就是说,对您的代码的其他评论:

  1. 一般来说,回叫R的速度很慢*,所以除非必须这样做,否则不要这样做,
  2. SEXP除非你知道自己在做什么,否则不要使用原始产品.在这里你很幸运,因为Lists的孩子被隐含地保护,但一般来说这是不安全的.
  3. 只需调用你的迭代器索引i,这是最常见的格式(看起来很奇怪ith).

事实证明,还有一个identical可用的C API .在RInternals.h,我们有

/* R_compute_identical:  C version of identical() function
   The third arg to R_compute_identical() consists of bitmapped flags for non-default options:
   currently all default to TRUE, so the flag is set for FALSE values:
   1 = !NUM_EQ
   2 = !SINGLE_NA
   4 = !ATTR_AS_SET
   8 = !IGNORE_BYTECODE
*/
Rboolean R_compute_identical(SEXP, SEXP, int);
Run Code Online (Sandbox Code Playgroud)

所以你可能只想用它.