在嵌套列表中处理值

时间:2019-08-20 16:24:36

标签: r json purrr

我正在尝试从API读取JSON元数据,在R中对其进行操作,然后回发。

但是,当我通过jsonlite获取元数据时,TRUE / FALSE值将被读取为逻辑值并变为大写。该API将不接受大写的TRUE / FALSE。因此,我需要将所有TRUE / FALSE替换为字符“ true”和“ false”,但保留与输入相同的嵌套列表结构。

问题在于这些是JSON键/值对和嵌套数组,因此true / false值嵌套在不同级别。我也只想更改“ TRUE”或“ FALSE”的值,而不更改包含“ true”或“ false”的字符串。

我尝试应用函数系列,purrr映射和递归循环。

#read data via API
dashitem_api<-paste0("api/metadata.json?filter=id:like:",dashitem_old_idprefix)
url<-paste0(baseurl,dashitem_api)

dash_items<-jsonlite::fromJSON(content(GET(url),"text")[])

...然后替换ID ....

编辑: ID的替换是将逻辑TRUE / FALSE值强制转换为字符串“ true” /“ false”。

详细说明的道歉...


    dashitem_old_idprefix<-"Ane0008"
    dashitem_new_idprefix<-"Ane0028"

    dash_items<-jsonlite::fromJSON(content(GET(url),"text")[])

    class(dash_items$charts$showData)
###output = "logical"

    #put all the replacement items into a list
    x1<-list(dashitem_old_idprefix,
             dashitem_new_idprefix)

    x2<-sapply(x1, function(x) as.character(x))

    replacements<-function(y){
      return(
        y %>% 
          gsub(x2[1], x2[2], .)
      )
    }

    new_dash <- rapply(dash_items, f = replacements, 
                       how = "replace")

    class(new_dash$charts$showData)
###output = "character"

R对象是一个列表,包含字符向量,命名列表,未命名列表,字符向量列表和数据帧,类似这样的

new_dash<-list(charts=list(list(id="abcd123",shared="FALSE",translations=list(),
                 dimensions=data.frame(thisyear="FALSE",last6Months="TRUE"),
params=list(reportingPeriod="FALSE",reportingUnit="FALSE"),
dimensionItems=list(type="DATA_ELEMENT",dataElement=list(id="ZYXW987"))),

               list(id="abcd4567",shared="FALSE",translations=list(),
                dimensions=data.frame(thisyear="FALSE",last6Months="TRUE"),
                params=list(reportingPeriod="FALSE",reportingUnit="TRUE"),
dimensionItems=list(type="DATA_ELEMENT",dataElement=list(id="ZYXW988")))),

reportTables=list(id="abcd124",title="false positives", shared="FALSE",translations=list(),
 dimensions=data.frame(thisyear="FALSE",last6Months="TRUE"),
params=list(reportingPeriod="FALSE",reportingUnit="FALSE"),
dimensionItems=list(type="DATA_ELEMENT",dataElement=list(id="ZYXW989"))))

我在网上找到了这些解决方案,但是我发现我需要使用真/假数据值指定列表的名称或位置,否则会出现错误,或者它以不需要的方式更改了new_dash文件(添加了新的嵌套列表)。

#solution 1
change_list <- function(x) {
  for (i in seq_along(x)) {
    value <- x[[i]]
    if (is.list(value)) {
      x[[i]] <- change_list(value)
    } else {
      if (as.character(value)=="FALSE") {
        x[[i]] <- tolower(value)
      }
    }
  }
  x
}
test1<-change_list(new_dash)

#solution 2
test2<-lapply(new_dash, function(x) {
  id <- x == "FALSE"
  x[id] <- "false"
  return(x)
})


#solution 3
test3<- c(map(new_dash$charts, 
~modify_if(~x=="TRUE", tolower)), 
recursive= TRUE)

我可能需要结合purify_if和Modify_at的purrr函数。或者,这是一种读取默认情况下不会转换为逻辑TRUE / FALSE的数据的替代方法。

FWIW,我是R新手,无论回答多么复杂或简单,我都会感谢您。

1 个答案:

答案 0 :(得分:1)

列表对象中的值实际上是"TRUE"(R字符串)还是TRUE(R逻辑)?如果它们是有效的R逻辑(与您共享的示例数据不同),那么jsonlite::toJSON将对其进行更正。

x <- list(
  partA = list(numbers = 1:3, boolean = T),
  partB = list(
    nested = list(
      numbers = 4:6, 
      nestB = list(boolean = c(FALSE, FALSE))
      )
    )
)

jsonlite::toJSON(x, pretty = T)
{
  "partA": {
    "numbers": [1, 2, 3],
    "boolean": [true]
  },
  "partB": {
    "nested": {
      "numbers": [4, 5, 6],
      "nestB": [
        {
          "boolean": false
        },
        {
          "boolean": false
        }
      ]
    }
  }
}

您似乎不太可能在数据处理步骤中生成"TRUE""FALSE"的字符串(已更新: 实际上是问题所在! ),因此希望它能奏效。 jsonlite::fromJSON[true, false]转换为c(TRUE, FALSE),而toJSON则相反。

确保将数据帧强制转换为相同格式可能需要进行一些检查。 toJSON有一些选择:dataframe =可以

  • ”(默认),
  • "nestB": {"boolean": [false, false]}
  • "nestB": [[false], [false]]

但是,如果您使用默认值来读取API响应,则不太可能需要更改默认值以将其发送回去。


已更新:

此用例正在调用rapply来搜索整个列表对象并替换某些元素。因为那是在调用gsub,所以每个元素都被强制为一个字符,包括任何数字或逻辑值。为防止这种情况,可以使用some_output_object <- rapply(some_input_object, f = some_replacing_function, how = "replace", classes = "character")。这样就不会保留数字和逻辑值,因此toJSON可以正确地将它们包装起来。