如何避免在使用R从JSON读取后循环列表

如何避免在使用R从JSON读取后循环列表,json,r,Json,R,我在R中有一个JSON数据向量,我用Lappy提取信息: list <- lapply(temp, fromJSON) 这适用于第一个元素:list[[1]]$hnrlbl,但如何一次对整个列表执行此操作?类似于list[.]$hnrlbl经过几个小时寻找最干净的方法,我们做到了: kadaster_building_temp$hnrlbl <- sapply(list,function(x){x$hnrlbl} ) 在这种情况下,您可以使用rlist包中的list.map:

我在R中有一个JSON数据向量,我用Lappy提取信息:

 list <- lapply(temp, fromJSON)

这适用于第一个元素:list[[1]]$hnrlbl,但如何一次对整个列表执行此操作?类似于list[.]$hnrlbl

经过几个小时寻找最干净的方法,我们做到了:

 kadaster_building_temp$hnrlbl <- sapply(list,function(x){x$hnrlbl} )

在这种情况下,您可以使用rlist包中的list.map:

警告:通过使用正则表达式,此解决方案在某些情况下可能会失败,具体取决于您在列表中使用的名称。如果速度不是一个选项,则list.map或使用sapply的解决方案都更可靠

通过在此处使用unlist并查找名称,您可以获得相当快的速度。选择以下函数:

这方面的基准:

require(rbenchmark)
benchmark(
  sapply(aList,function(i)i$z),
  myselect(aList,"z"),
  columns=c("test","elapsed","relative"),
  replications=10000
  )

                            test elapsed relative
2           myselect(aList, "z")    0.24    1.000
1 sapply(aList, function(i) i$z)    0.39    1.625
对于较大的对象,改进可能是实质性的。在我的工作区dput中碰巧有一个列表上使用此选项在这里不是一个选项…:

> benchmark(
+   sapply(StatN0_1,function(i)i$SP),
+   myselect(StatN0_1,"SP"),
+   columns=c("test","elapsed","relative"),
+   replications=100
+ )
                                test elapsed relative
2           myselect(StatN0_1, "SP")    0.02      1.0
1 sapply(StatN0_1, function(i) i$SP)    1.13     56.5

我有一个助手函数,它对这些场景非常有用:

pluck <- function(x, name, type) {
  if (missing(type)) {
    lapply(x, .subset2, name)
  } else {
    vapply(x, .subset2, name, FUN.VALUE = type)
  }
}
也可以按位置选择:X、2、字符10

标杆管理 这种方法也很快:

x_big <- rep(x, 1000)

myselect <- function(x,name){
  tmp <- unlist(x, recursive = FALSE)
  id <- grep(paste0("\\.",name,"$"), names(tmp))
  tmp[id]
}

library(microbenchmark)
options(digits = 2)
microbenchmark(
  sapply(x_big, function(i)i$z),
  myselect(x_big,"z"),
  pluck(x_big, "z", character(1))
)
#> Unit: microseconds
#>                             expr  min   lq median   uq  max neval
#>   sapply(x_big, function(i) i$z) 2771 2886   2972 3124 5903   100
#>             myselect(x_big, "z") 2250 2330   2366 2401 3551   100
#>  pluck(x_big, "z", character(1))  717  786    825  889 1731   100

您想从每个列表项中提取hnrlbl?能否提供dputlist?另外,你认为LUpEt是循环的吗?@ McEeleNeaRe:是的,这正是我想要的。do@DavidArenburg不,我不认为LoPipe是循环的,那就好了。你觉得我的回答怎么样?如果你看到一些更干净、更快的东西,我很高兴给你发一份清单。它看起来是解决这类问题的常用方法,而且是一种简单的方法。由于list.map基于mapply,因此它仍然是一个内在循环函数,速度不一定比sapply快。此方法假定顶级列表已命名,使用正则表达式将非常脆弱。@hadley改编为允许使用未命名的顶级列表。我同意使用易损坏的正则表达式,这就是为什么我强调在这种特殊情况下这是为了提高速度。我加了一句话来反映这一点。换言之:为速度而放弃安全的人,两者都不配。
require(rbenchmark)
benchmark(
  sapply(aList,function(i)i$z),
  myselect(aList,"z"),
  columns=c("test","elapsed","relative"),
  replications=10000
  )

                            test elapsed relative
2           myselect(aList, "z")    0.24    1.000
1 sapply(aList, function(i) i$z)    0.39    1.625
> benchmark(
+   sapply(StatN0_1,function(i)i$SP),
+   myselect(StatN0_1,"SP"),
+   columns=c("test","elapsed","relative"),
+   replications=100
+ )
                                test elapsed relative
2           myselect(StatN0_1, "SP")    0.02      1.0
1 sapply(StatN0_1, function(i) i$SP)    1.13     56.5
pluck <- function(x, name, type) {
  if (missing(type)) {
    lapply(x, .subset2, name)
  } else {
    vapply(x, .subset2, name, FUN.VALUE = type)
  }
}
x <- list(
  a = list(x = rnorm(10), y = letters[1:10], z = "OK"),
  b = list(x = rnorm(10), y = letters[11:20], z = "notOK")
)

# List of results
str(pluck(x, "z"))
#> List of 2
#>  $ a: chr "OK"
#>  $ b: chr "notOK"

# Vector of results
str(pluck(x, "z", character(1)))
#>  Named chr [1:2] "OK" "notOK"
#>  - attr(*, "names")= chr [1:2] "a" "b"
x_big <- rep(x, 1000)

myselect <- function(x,name){
  tmp <- unlist(x, recursive = FALSE)
  id <- grep(paste0("\\.",name,"$"), names(tmp))
  tmp[id]
}

library(microbenchmark)
options(digits = 2)
microbenchmark(
  sapply(x_big, function(i)i$z),
  myselect(x_big,"z"),
  pluck(x_big, "z", character(1))
)
#> Unit: microseconds
#>                             expr  min   lq median   uq  max neval
#>   sapply(x_big, function(i) i$z) 2771 2886   2972 3124 5903   100
#>             myselect(x_big, "z") 2250 2330   2366 2401 3551   100
#>  pluck(x_big, "z", character(1))  717  786    825  889 1731   100