从列表中提取非空元素

40

我有一个像这样的列表:

    x = list(a = 1:4, b = 3:10, c = NULL)
    x
    #$a
    #[1] 1 2 3 4
    #
    #$b
    #[1]  3  4  5  6  7  8  9 10
    #
    #$c
    #NULL

我想提取所有不为空的元素。这该怎么做?谢谢。

5个回答

51

这里有另一个选择:

Filter(Negate(is.null), x)

13
x[!sapply(x,is.null)]

这适用于列表的任何逻辑语句,只需将“is.null”的逻辑替换即可。


13

怎么样:

x[!unlist(lapply(x, is.null))]

以下是正在发生的事情的简要描述。

  1. lapply告诉我们哪些元素是NULL

R> lapply(x, is.null)
$a
[1] FALSE

$b
[1] FALSE

$c
[1] TRUE
  • 接下来我们将列表转换为向量:

    R> unlist(lapply(x, is.null)) 
    a     b     c 
    FALSE FALSE  TRUE 
    
  • 然后我们把TRUE改成FALSE:

  • R> !unlist(lapply(x, is.null))
        a     b     c 
    TRUE  TRUE FALSE 
    
  • 最后,我们使用通常的符号选择元素:

  • x[!unlist(lapply(x, is.null))]
    

    7
    x[!sapply(x, is.null)]会更快吗? - Julius Vainora

    1
    比上面更简单且可能更快的方法适用于任何非递归(在 is.recursive 的意义下)值的列表:
    example_1_LST <- list(NULL, a=1.0, b=Matrix::Matrix(), c=NULL, d=4L)
    example_2_LST <- as.list(unlist(example_1_LST, recursive=FALSE))
    

    str(example_2_LST) 打印输出:

    List of 3
     $ a: num 1
     $ b:Formal class 'lsyMatrix' [package "Matrix"] with 5 slots
      .. ..@ x       : logi NA
      .. ..@ Dim     : int [1:2] 1 1
      .. ..@ Dimnames:List of 2
      .. .. ..$ : NULL
      .. .. ..$ : NULL
      .. ..@ uplo    : chr "U"
      .. ..@ factors : list()
     $ d: int 4
    

    您无需使用 base::utils:: 来引用基础和工具函数。 - Rich Scriven

    1

    一种选择是使用%in%

    x[!x %in% list(NULL)]
    #$a
    #[1] 1 2 3 4
    #
    #$b
    #[1]  3  4  5  6  7  8  9 10
    

    vapply中,或者使用is.null

    x[!vapply(x, is.null, FALSE)]
    

    或者使用 lengths,但如果列表包含例如numeric(0),这将失败
    x[lengths(x) > 0]
    

    基准测试

    x = list(a = 1:4, b = 3:10, c = NULL)
    bench::mark(
    sapply = x[!sapply(x,is.null)],
    Filter = Filter(Negate(is.null), x),
    "in" = x[!x %in% list(NULL)],
    lapply = x[!unlist(lapply(x, is.null))],
    vapply = x[!vapply(x, is.null, FALSE)],
    lengths = x[lengths(x) > 0] )
    #  expression     min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
    #  <bch:expr> <bch:t> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
    #1 sapply     19.85µs 22.73µs    40853.        0B    12.3   9997     3    244.7ms
    #2 Filter     11.84µs 13.73µs    70067.        0B    14.0   9998     2    142.7ms
    #3 in          9.87µs 11.45µs    81415.        0B     8.14  9999     1    122.8ms
    #4 lapply       6.4µs  7.49µs   126673.        0B    12.7   9999     1     78.9ms
    #5 vapply      4.64µs  5.51µs   177842.        0B    17.8   9999     1     56.2ms
    #6 lengths     2.12µs  2.32µs   414271.        0B     0    10000     0     24.1ms
    

    实际上,对于包开发,应该像你在这里建议的那样使用vapply()函数。 我实际上会稍微以不同的方式编写它。请看下面的代码: x[!vapply(x, is.null, logical(length = 1L))] 不知道这种方式与使用FALSE有多大的不同,或者它是否对基准测试有影响。有任何想法吗? - undefined
    1
    logical(length = 1L) 返回 FALSE。在基准测试中,我不会期望有任何差异。 - undefined

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接