【问题标题】:Iterate over S4 object slots Rcpp迭代 S4 对象槽 Rcpp
【发布时间】:2015-06-11 05:24:35
【问题描述】:

是否可以遍历S4 对象槽?

到目前为止,我能够想出这个。但我真的很想避免调用 R 函数slotNames。是否有可能在 C/C++ 级别上做同样的事情?

// [[Rcpp::export]]
void foo(SEXP x) {
  Rcpp::S4 obj(x);
  Function slotNames("slotNames"); 
  CharacterVector snames = slotNames(obj);
  for (int i = 0; i < snames.size(); i++) {
    SEXP slot = obj.slot(Rcpp::as<std::string>(snames[i]));
    // do something with slot
  }
}

【问题讨论】:

  • IMO 我认为您不会因一次调用 slotNames 而导致显着的性能成本。
  • 同意@nrussell;你能说为什么你想避免slotNames吗?
  • @ben-bolker 我知道一个函数调用不会对性能产生很大影响。我需要这个,因为我正在为 R 编写一个详细的跟踪器,它写下调用的参数。为了避免递归评估,它分支到 C/C++,在其中将参数写入文件。所以我想避免回到 R

标签: r rcpp


【解决方案1】:

看着R source code,我看到这样的东西:

/**
 * R_has_slot() : a C-level test if a obj@<name> is available;
 *                as R_do_slot() gives an error when there's no such slot.
 */
int R_has_slot(SEXP obj, SEXP name) {

#define R_SLOT_INIT                         \
    if(!(isSymbol(name) || (isString(name) && LENGTH(name) == 1)))  \
    error(_("invalid type or length for slot name"));       \
    if(!s_dot_Data)                         \
    init_slot_handling();                       \
    if(isString(name)) name = installChar(STRING_ELT(name, 0))

    R_SLOT_INIT;
    if(name == s_dot_Data && TYPEOF(obj) != S4SXP)
    return(1);
    /* else */
    return(getAttrib(obj, name) != R_NilValue);
}

我想这意味着您可以使用 getAttrib 将其拖出。

所以,今天我了解到 S4 插槽实际上只是特殊属性,这些属性可以通过 @ 访问。观察:

> setClass("Foo", list(apple = "numeric"))
> foo <- new("Foo", apple = 1)
> foo@apple
[1] 1
> attributes(foo)
$apple
[1] 1

$class
[1] "Foo"
attr(,"package")
[1] ".GlobalEnv"

> foo@class
[1] "Foo"
attr(,"package")
[1] ".GlobalEnv"
> attr(foo, "bar") <- 2
> foo@bar
[1] 2

希望这至少可以为您提供一个开始的地方。

【讨论】:

  • 然而,这被视为实现细节,可能会在没有任何警告的情况下更改。虽然这不太可能。
猜你喜欢
  • 2016-06-09
  • 1970-01-01
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多