关于 r:对嵌套列表中的 NULL 元素应用替换功能


Applying replacement function for NULL elements in nested lists

我正在从一个公寓租赁平台的 rest api 中抓取 json。

假设我有以下数据结构,它传达了单个建筑物中每个出租单元的平方英尺:

1
2
3
sqft1 <- list(c("1500"),
              NULL,
              c("1300"))

保留这些数据的维度很重要。如果我尝试与其他出租单元属性一起取消列出并聚合到数据框中,我将丢失第二个元素并引发错误。

但是通过在列表中找到具有 NULL 元素的索引,我可以将它们替换为包含空字符串的字符向量,如下所示:

1
2
isNull1 <- lapply(1:length(sqft1), function(x) is.null(sqft1[[x]]))
sqft1[unlist(isNull1)] <- c("")

当我尝试对多个建筑物的结果集应用相同的替换函数时,我的问题出现了。运行以下块后,不会进行任何替换。

1
2
3
4
5
6
7
8
9
sqft3 <- list(list(c("1500"),
                   NULL,
                   c("1300")),
              list(c("1400"),
                   c("1700")),
              list(NULL,
                   c("1200")))
isNull3 <- lapply(1:length(sqft3), function(x) lapply(1:length(sqft3[[x]]), function(y) is.null(sqft3[[x]][[y]])))
lapply(1:length(sqft3), function(x) sqft3[[x]][unlist(isNull3[[x]])] <- c(""))

我在这里误解了关于应用函数的什么概念?任何想法如何使它工作?

谢谢!


你可以使用嵌套的 lapply 如下

1
lapply(sqft3, function (x) lapply(x, function (y) ifelse(is.null(y),"", y)))

这类似于@MKR 的解决方案。

使用 purrr 包,你也可以使用 modify_depth

1
2
library(purrr)
modify_depth(sqft3, .depth = 2, .f =  ~ifelse(is.null(.x),"", .x))

上面的ifelse也可以被这个函数%||%("null-default",同样来自purrr)替换,如下

1
modify_depth(sqft3, 2, `%||%`,"")

(%||%if (is.null(x)) y else x 的简写)

结果

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
#[[1]]
#[[1]][[1]]
#[1]"1500"
#
#[[1]][[2]]
#[1]""
#
#[[1]][[3]]
#[1]"1300"
#
#
#[[2]]
#[[2]][[1]]
#[1]"1400"
#
#[[2]][[2]]
#[1]"1700"
#
#
#[[3]]
#[[3]][[1]]
#[1]""
#
#[[3]][[2]]
#[1]"1200"


一种选择是使用 map 函数两次:

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
map(sqft3,function(x){
  map(x, function(y){
    y[is.null(y)] <-""
    y
  })})


# [[1]]
# [[1]][[1]]
# [1]"1500"
#
# [[1]][[2]]
# [1]""
#
# [[1]][[3]]
# [1]"1300"
#
#
# [[2]]
# [[2]][[1]]
# [1]"1400"
#
# [[2]][[2]]
# [1]"1700"
#
#
# [[3]]
# [[3]][[1]]
# [1]""
#
# [[3]][[2]]
# [1]"1200"

数据:

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
sqft3 <- list(list(c("1500"),
          NULL,
          c("1300")),
     list(c("1400"),
          c("1700")),
     list(NULL,
          c("1200")))

sqft3
# [[1]]
# [[1]][[1]]
# [1]"1500"
#
# [[1]][[2]]
# NULL
#
# [[1]][[3]]
# [1]"1300"
#
#
# [[2]]
# [[2]][[1]]
# [1]"1400"
#
# [[2]][[2]]
# [1]"1700"
#
#
# [[3]]
# [[3]][[1]]
# NULL
#
# [[3]][[2]]
# [1]"1200"