【问题标题】:How to access very first object in differently deep nested lists?如何访问不同深度嵌套列表中的第一个对象?
【发布时间】:2022-02-02 14:10:31
【问题描述】:

我需要访问list 的第一个元素。问题在于列表的嵌套深度不同。这是一个例子:

list1 <- list(ts(1:100),
              list(1:19,
                   factor(letters)))

list2 <- list(list(list(ts(1:100), data.frame(a= rnorm(100))),
                   matrix(rnorm(10))),
              NA)

我的预期输出是获得两个列表的时间序列ts(1:100),即list1[[1]]list2[[1]][[1]][[1]]。我尝试了不同的东西,其中包括 lapply(list2, `[[`, 1) 在这里不起作用。

【问题讨论】:

  • 所以我们只想提取ts类对象?
  • @zx8754 在这个例子中是的。

标签: r list select nested-lists


【解决方案1】:

另一种基本 R 解决方案 - 您可以使用递归函数来做到这一点:

list1 <- list(ts(1:100),
              list(1:19,
                   factor(letters)))

list2 <- list(list(list(ts(1:100), data.frame(a= rnorm(100))),
                   matrix(rnorm(10))),
              NA)


recursive_fun <- function(my_list) {
  
  if (inherits(my_list, 'list')) {
    Recall(my_list[[1]])
  } else {
    my_list
  }
  
}

输出:

> recursive_fun(list1)
Time Series:
Start = 1 
End = 100 
Frequency = 1 
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30
 [31]  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60
 [61]  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
 [91]  91  92  93  94  95  96  97  98  99 100

> recursive_fun(list2)
Time Series:
Start = 1 
End = 100 
Frequency = 1 
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30
 [31]  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60
 [61]  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
 [91]  91  92  93  94  95  96  97  98  99 100

【讨论】:

  • is.list() 也会在data.frame 上返回TRUE。我认为inherits(my_list, 'list')更好。
  • @sindri_baldur 是的,我同意这一点-也许length(my_list) &gt; 0if 条件下,以防万一有一个空列表也值得做
【解决方案2】:

你可以使用rrapply::rrapply:

library(rrapply)
firstList1 <- rrapply(list1, how = "flatten")[[1]]
firstList2 <- rrapply(list2, how = "flatten")[[1]]

all.equal(firstList1, firstList2)
# [1] TRUE

输出

> rrapply(list1, how = "flatten")[[1]]

Time Series:
Start = 1 
End = 100 
Frequency = 1 
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26
 [27]  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52
 [53]  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78
 [79]  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100

【讨论】:

    【解决方案3】:

    我们可以将while 循环与purrr::pluck 结合起来。这避免了实际的递归函数,这可能是深度嵌套列表的问题。

    library(purrr)
    
    get_list <- function(x){
            while(is.list(x)){
                    x <- pluck(x, 1)
                    }
            x
    }
    

    我们还可以将函数设置为“递归”调用,直到找到“ts”类对象:

    get_list <- function(x){
            while(!is(x, 'ts')){
                    x <- pluck(x, 1)
                    }
            x
    }
    

    输出

    
    get_list(list2)
    
    Time Series:
    Start = 1 
    End = 100 
    Frequency = 1 
      [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45
     [46]  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
     [91]  91  92  93  94  95  96  97  98  99 100
    

    【讨论】:

    • 这是一个有趣的方法。两个问题:你写了“递归函数,这可能是深度嵌套列表的问题”——递归函数在什么方面遇到了麻烦,为什么 while 循环能更好地掌握这种情况?还有:pluck(x, 1)x[[1]] 相比有什么好处?
    • 嗨,@stats.and.r。它更像是一个概念性的东西。表面递归在 R 中是可以的。但深度递归函数可能会溢出 C 堆栈。试试下面的例子:i &lt;- 1 infinite_recursion &lt;- function(){ i &lt;&lt;- i + 1 infinite_recursion() } infinite_recursion() - 这将创建一个递归函数,该函数总是在错误“错误:C 堆栈使用 7974324 太接近限制”处停止。我的机器上有i = 865。尽管这很少会危及任何带有几个递归循环的过程,但这说明了递归函数通常的脆弱性。
    • 至于我更喜欢​​pluck 而不是[[]],我想这只是因为我是tidyverse 的粉丝,所以我很自然地最终会尽可能地使用purrr 来处理列表。 pluck dos 通过双括号的基本索引提供了一些通用性,检查文档,你会看到。对于当前的用例,我同意[[]] 实际上更直接
    • 对我的第一条评论的补充。使用while 检查有问题的infinite_recursion 函数的替代方法:infinite_while &lt;- function(){ while(TRUE) i&lt;&lt;-i+1 } infinite_while() - 这在实际的无限循环中运行,不会导致“C 堆栈溢出”问题。大约 10 秒后我停止了函数调用,得到了i = 114072514
    • 您好,感谢 cmets 的回答! +1
    【解决方案4】:

    另一种可能的解决方案,使用purrr::pluckpurrr::vec_depth

    library(tidyverse)
    
    pluck(list1, !!!(rep(1, vec_depth(list1)-2) %>% as.list()))
    
    #> Time Series:
    #> Start = 1 
    #> End = 100 
    #> Frequency = 1 
    #>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
    #>  [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
    #>  [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
    #>  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
    #>  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
    #>  [91]  91  92  93  94  95  96  97  98  99 100
    
    pluck(list2, !!!(rep(1, vec_depth(list2)-2) %>% as.list()))
    
    #> Time Series:
    #> Start = 1 
    #> End = 100 
    #> Frequency = 1 
    #>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
    #>  [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
    #>  [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
    #>  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
    #>  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
    #>  [91]  91  92  93  94  95  96  97  98  99 100
    

    【讨论】:

      【解决方案5】:

      基础 R 解决方案 我刚刚想到了一个非常简单的函数。这是一个while 循环,一直运行到元素不是列表为止。

      myfun <- function(mylist){
        dig_deeper <- TRUE
        while(dig_deeper){
          mylist<- my_list[[1]]
          dig_deeper <- is.list(mylist)
        }
        return(mylist)
      }
      

      按预期工作

      > myfun(list1)
      Time Series:
      Start = 1 
      End = 100 
      Frequency = 1 
        [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24
       [25]  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48
       [49]  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
       [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96
       [97]  97  98  99 100
      

      【讨论】:

        【解决方案6】:

        使用while 循环:

        x <- list1
        while (inherits(x <- x[[1]], "list")) {}
        x
        #> Time Series:
        #> Start = 1 
        #> End = 100 
        #> Frequency = 1 
        #>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
        #>  [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
        #>  [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
        #>  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
        #>  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
        #>  [91]  91  92  93  94  95  96  97  98  99 100
        
        x <- list2
        while (inherits(x <- x[[1]], "list")) {}
        x
        #> Time Series:
        #> Start = 1 
        #> End = 100 
        #> Frequency = 1 
        #>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
        #>  [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
        #>  [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
        #>  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
        #>  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
        #>  [91]  91  92  93  94  95  96  97  98  99 100
        

        【讨论】:

        • 喜欢这么短的代码!与此相比,我的带有 while 循环的代码似乎很麻烦。
        猜你喜欢
        • 1970-01-01
        • 2022-11-04
        • 1970-01-01
        • 2013-10-12
        • 1970-01-01
        • 2020-08-02
        • 1970-01-01
        • 2019-02-03
        • 1970-01-01
        相关资源
        最近更新 更多