使用 Rcpp 检查列表失败

Checking for a list using Rcpp fails

使用 Rcpp 考虑这些示例以检查各种数据类型。为什么我检查 is_list return FALSE?

library(Rcpp)

cppFunction('bool is_list(SEXP data) {
  return Rf_isList(data) ? true : false;
}')

cppFunction('bool is_data_frame(SEXP x) {
    return Rf_inherits(x, "data.frame") ? true : false;
}')

cppFunction('bool is_integer(SEXP data) {
  return Rf_isInteger(data) ? true : false;
}')

is_data_frame(list(a = 1))
# [1] FALSE
is_data_frame(data.frame())
# [1] TRUE
is_integer(1)
# [1] FALSE
is_integer(1L)
# [1] TRUE

## However, this is unexpected
is_list(list(a = 1))
[1] FALSE

参考资料

这可能是 R。考虑这两个针对 R API 的普通 C 函数,它们复制了您的结果,但不涉及任何 Rcpp:

R> library(inline)
R> f <- cfunction(signature(s="SEXP"), body="SEXP b = PROTECT(allocVector(INTSXP, 1)); INTEGER(b)[0] = Rf_isList(s); UNPROTECT(1); return b;")
R> f(list(a=1))
[1] 0
R> g <- cfunction(signature(s="SEXP"), body="SEXP b = PROTECT(allocVector(INTSXP, 1)); INTEGER(b)[0] = Rf_inherits(s, \"data.frame\"); UNPROTECT(1); return b;")
R> g(data.frame(a=1))
[1] 1
R> 

所以本质上 Rf_isList() 似乎遗漏了列表类型。这背后可能有一个很好的理由,但我现在不能说出它的名字......

我们在 src/include/Rinlinedfuns.h

中稍微挖掘一下
INLINE_FUN Rboolean isList(SEXP s)
{
    return (s == R_NilValue || TYPEOF(s) == LISTSXP);
}

这让我们很难看出哪里出了问题。但也许你想戳那里...

改用Rf_isNewList。 (显然列表的表示在某些时候发生了变化。)

这个有效:

library(Rcpp)

cppFunction('bool is_list(SEXP data) {
    return Rf_isNewList(data) ? true : false;
}')

is_list(list(a = 1))
#> TRUE

is_list(1)
#> FALSE

我认为改为执行以下操作更为惯用:

cppFunction('bool is_list(SEXP data) {
    return (TYPEOF(data) == VECSXP);
}')

这有 NULL 不是列表的副作用。