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

时间:2014-08-26 10:22:28

标签: json r

我在R中有一个JSON数据向量,并且lapply我提取信息:

 list <- lapply(temp, fromJSON)

此列表的第一个元素的结构如下所示:

str(list[[1]])

List of 4
 $ boundedBy :List of 2
  ..$ type       : chr "Polygon"
  ..$ coordinates:List of 1
  .. ..$ :List of 5
  .. .. ..$ : num [1:2] 89328 208707
  .. .. ..$ : num [1:2] 89333 208707
  .. .. ..$ : num [1:2] 89333 208713
  .. .. ..$ : num [1:2] 89328 208713
  .. .. ..$ : num [1:2] 89328 208707
 $ hnrlbl    : NULL
 $ opndatum  : chr "2011-05-30"
 $ oidn      : chr "2954841"

这适用于第一个元素:list[[1]]$hnrlbl,但如何为整个列表立即执行此操作?像list[[.]]$hnrlbl

这样的东西

4 个答案:

答案 0 :(得分:4)

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

mylist <- lapply(temp, fromJSON)
library(rlist)
list.map(mylist, hnrlbl)

http://cran.r-project.org/web/packages/rlist/vignettes/Mapping.html

答案 1 :(得分:3)

我有一个对这些场景有用的辅助函数:

pluck <- function(x, name, type) {
  if (missing(type)) {
    lapply(x, .subset2, name)
  } else {
    vapply(x, .subset2, name, FUN.VALUE = type)
  }
}

(这是受underscore和温斯顿的启发 长安。 .subset2()[[的内部版本 - 它更快,但是 不执行S3调度,这意味着x需要是一个普通列表。

使用此功能,解决您的问题很容易:

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"

(您也可以按位置选择:pluck(x, 2, character(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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

警告:通过使用正则表达式,此解决方案可能会在某些情况下失败(具体取决于您在列表中使用的名称)。如果无法选择速度,则list.map或使用sapply的解决方案更加健壮


在这里使用unlist()并查找名称可以获得相当快的速度。采用以下函数myselect

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

这个做的大致相同,但是以矢量化的方式。通过使用参数recursive=FALSE,您可以将嵌套列表展平为平面列表(所有元素都是同一列表的一部分)。然后使用此函数使用的命名约定来查找包含要选择的确切名称的所有元素。因此调用paste0来构造一个避免部分名称匹配的正则表达式。简单选择将再次返回包含所需元素的列表。如果您希望这是一个向量左右,您可以在结果上使用unlist()

请注意,我假设您有一个列表列表,因此您只想展平一个级别。对于更复杂的嵌套,这显然不适用于当前形式。


示例和基准测试

速度增益显然取决于列表的结构,但可以达到50倍或更高的速度增益。

采取以下(非常基本的)示例:

aList <- list(
  a=list(x=rnorm(10),y=letters[1:10],z="OK"),
  b=list(x=rnorm(10),y=letters[11:20],z="notOK")
  )

对此进行基准测试得出:

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