如何递归检查列表是否包含列表

how to check if list contains lists recursively

我在 R 中有一个函数可以递归地构建不同深度列表的列表。输出 node 可能是

node<-list(right=(0))

node<-list(right=list(right=0))

在 Rcpp 中,我想构建一个递归解构列表和 return 整数成员,在本例中为 0。

我的问题是检查 node 是否有命名成员 right

library(Rcpp)

cppFunction(
'
int predict(List node){
   if(node["right"]){
     return predict(node["right"]);
   }
   else{
     return node;
   }
 }
}
'
)

我看过 Dynamic Wrapping 检查类型并使用 switch/case,但它似乎不喜欢命名列表。

您可以只获取名称并检查是否有元素 right

以下代码应该有效:

library(Rcpp)

cppFunction(
  '
  int predict(List node) {
    std::vector<std::string> list_names = node.names();
    if (std::find(list_names.begin(), list_names.end(), "right") != list_names.end()) {
      if (TYPEOF(node["right"]) == REALSXP) {
        return node["right"];
      } else {
        return predict(node["right"]);
      }
    } else {
      return -1;
    }
  }
  '
)

结果

> node<-list(right=(0))
> predict(node)
[1] 0
> node<-list(right=list(right=0))
> predict(node)
[1] 0

尝试使用子集检查命名值是否存在,例如if(node["right"]),会触发以下错误:

Error in predict_bad(node) : Not compatible with requested type: [type=list; target=logical].

要在 List*Vector 中搜索命名元素,请使用 .containsElementNamed("name") 成员函数。

例如,我们有:

#include<Rcpp.h>

// [[Rcpp::export]]
Rcpp::List predict_list(Rcpp::List node){

    // Check if name is present
    if(node.containsElementNamed("right")) {
        return predict_list(node["right"]);
    }

    return node;
}

注意,这里我们返回一个Rcpp::List,例如

node1 = list(right = list(right = 0))  
predict_list(node1)
# [[1]]
# [1] 0

要只获取一个整数,我们必须首先子集列表并强制转换到适当的类型。第二个组件,如果我们足够狡猾,我们可以让 Rcpp automagic 处理转换。 (感谢张强透露之前的回答不是一定要限位吗。)

#include<Rcpp.h>

// [[Rcpp::export]]
int predict_node_val(Rcpp::List node) {

    // Check if name is present
    if(node.containsElementNamed("right")) {

        // Check if element isn't a list.
        switch(TYPEOF(node["right"])) {
        case REALSXP:
        case INTSXP:
            return node["right"];
        default: // Keep going down the tree
            return predict_node_val(node["right"]);
        }

    }

    // Quiet compiler by providing a final output case
    return -1;
}

输出:

node1 = list(right = list(right = 0))  
node2 = list(right = 0)  
predict_node_val(node1)
# [1] 0
predict_node_val(node2)
# [1] 0

上面做了一些假设...首先是我们将总是有一个基于类型的列表架构。第二个是我们要检索的值总是列为 "right"。第三个