【问题标题】:Recursive object-listing递归对象列表
【发布时间】:2013-05-16 18:07:30
【问题描述】:

R 中是否有一种优雅的方法可以将任意深度列表(包含列表和向量)递归地转换为路径向量?例如,转换这个:

list(
  home = list(
    jerry = c("R", "bla"),
    mary = "xx"
  ),
  tmp = c("foo", "bar"),
  c("etc")
)

到这样的对象:

c(
  "/home/jerry/R",
  "/home/jerry/bla",
  "/home/mary/xx",
  "/tmp/foo",
  "/tmp/bar",
  "/etc"
 )

【问题讨论】:

    标签: r list


    【解决方案1】:

    只要您的列表元素中没有包含点的名称(除了列表中那个麻烦的NULL-valued etc 元素),这应该可以工作:

    ll <- rapply(l, function(X) sapply(X,list), how="replace") #for tip element names
    nms <- names(unlist(ll))
    gsub(".", "/", nms, fixed=TRUE)
    # [1] "home/jerry/R"   "home/jerry/bla" "home/mary/xx"   "tmp/foo"       
    # [5] "tmp/bar"    
    

    【讨论】:

    • 谢谢。我已将 etc 更改为向量而不是名称。现在效果很好。
    【解决方案2】:

    对于更通用的方法,包括可能带有点和空元素的名称,请使用:

    f <- function(test, parent=character(0))
    {
        if( is.null(test) ) return(parent)
    
        if( is.list(test) )
        {
            result <- character(0)
    
            for( i in seq_along(test) )
            {
                result <- c(result, Recall(test[[i]], parent=paste0(parent,"/",names(test)[i])))
            }
        }
        else
        {
            result <- paste0(parent,"/",as.character(test))
        }
    
        result
    }
    
    f(test)
    
    #[1] "/home/jerry/R"   "/home/jerry/bla" "/home/mary/xx"   "/tmp/foo"        "/tmp/bar"        "/etc" 
    

    【讨论】:

    • 酷。大量使用 Recall 递归调用匿名函数。
    • 超级。谢谢你。我相信我将来会用它作为其他树遍历函数的模板。
    • :-) @JoshO'Brien,关键的想法是有一个参数来跟踪你的深度级别(默认为零或 null 或类似的东西)。
    • @Jeroen,从技术上讲,该函数不是匿名的,因为它绑定到一个符号 (f)。我选择了Recall 以避免错误,以防万一将其分配给其他符号。
    【解决方案3】:

    unlist 中的名称大致符合您的要求:

    > test <- list(
    +     home = list(
    +         jerry = c("R", "bla"),
    +         mary = "xx"
    +     ),
    +     tmp = c("foo", "bar"),
    +     etc = c()
    + )
    > unlist(test)
    home.jerry1 home.jerry2   home.mary        tmp1        tmp2 
            "R"       "bla"        "xx"       "foo"       "bar" 
    

    也可以处理多级递归:

    > test <- list(
    +     home = list(
    +         jerry = list(a="R", b="bla"),
    +         mary = list(c="xx")
    +     ),
    +     tmp = list(d="foo", e="bar"),
    +     etc = list(nothing=NULL)
    + )
    > unlist(test)
    home.jerry.a home.jerry.b  home.mary.c        tmp.d        tmp.e 
             "R"        "bla"         "xx"        "foo"        "bar" 
    

    从那里很容易添加你想要的最后一点(最终值是最后一个路径元素):

    > unl <- unlist(test)
    > res <- names(unl)
    > res <- paste(res,unl,sep=".")
    > res
    [1] "home.jerry.a.R"   "home.jerry.b.bla" "home.mary.c.xx"   "tmp.d.foo"        "tmp.e.bar"       
    

    【讨论】:

      猜你喜欢
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-14
      相关资源
      最近更新 更多