简体   繁体   中英

How do I get attributes of list elements recursively in R?

I have a nested list structure with some elements (not all) having attributes that I want to keep (I've converted some xml output to a list ). I'm trying to flatten it into a data.frame . The structure is something like this:

myList <- structure(list(address = structure(list(Address = list(Line = list("xxxxxxx"), 
                                          Line = list("xxxxxxx"), Line = list("xxxxxxx"), PostCode = list(
                                            "XXX XXX"))), type = "Residential", verified = "Unverified"), 
amount = structure(list(paymentAmount = list(maxAmount = list(
  amountPart = structure(list(Amount = list("0.00")), component = "Standard"), 
  amountPart = structure(list(Amount = list("0.00")), component = "Thing1"), 
  amountPart = structure(list(Amount = list("0.00")), component = "Thing2"), 
  amountPart = structure(list(Amount = list("0.00")), component = "Thing3"), 
  amountPart = structure(list(Amount = list("0.00")), component = "Thing4"), 
  amountPart = structure(list(Amount = list("100.00")), component = "Thing5"), 
  amountPart = structure(list(Amount = list("0.00")), component = "Thing6")), 
  otherAmount = list(Amount = list("0.00")), 
  discount = list("0.00"), 
  transition = list(
    "0.00"), discounts = list(), regularPayment = list(
      "200.00")), 
  paymentInfo = list(income = structure(list(
        net = list("0")), refNumber = "xxxxxxx"))), 
  paymentDate = "2021-03-22", startDate = "2021-02-16", endDate = "2021-03-15")), 
type = "Normal")

I've tried rapply(myList, attributes) but that just seems to return NULL .

I've also tried using a loop in a recursive function:

get_attributes <- function(myList, attribute_list = NULL) {
  if (is.null(attribute_list)) attribute_list <- list()
  for (i in seq_along(myList)) {
    if (is.list(myList[[i]])) {
      attribute_list <- c(attribute_list, sapply(myList[[i]], attributes))
      attribute_list <- get_attributes(myList[[i]], attribute_list)
    } else {
      attribute_list <- c(attribute_list, attributes(myList[[i]]))
    }
  }
  attribute_list
}

Once I've got the list of attributes, I then want to put them in a one row data.frame - something like data.frame(address.type = "Residential", address.verified = "Unverified", component.1 = "Standard", component.2 = "Thing1"

The function with a loop is a bit messy and not very 'R', and it also seems to spit out lots of repeated elements that I don't want. Does anyone have any idea how to implement this more elegantly?

UPDATE

I've refined the loop implementation to this, which seems to work, but I just couldn't figure out how to use either purrr or one of the *apply functions in place of the loop:

get_attributes <- function(myList, attribute_list = NULL, prefix = NULL) {
  
  if (is.null(attribute_list)) {
    attribute_list <- list()
  }
  if (is.null(prefix)) {
    prefix <- ""
  }
  
  for (i in seq_along(myList)) {
    name <- names(myList)[i]
    attrs <- attributes(myList[[i]])
    if (!is.null(attrs)) {
      names(attrs) <- paste0(prefix, name, ".", names(attrs))
      attrs <- attrs[!grepl("\\.names$", names(attrs))]
      attribute_list <- c(attribute_list, attrs)
    }
    if (is.list(myList[[i]])) {
      attribute_list <- get_attributes(myList[[i]],
                                       attribute_list,
                                       paste0(prefix, name, "."))
    }
  }

  attribute_list
  
}

do.call(data.frame, get_attributes(myList))

You can gather all the attributes available and just keep the ones you are interested from it.

library(purrr)

map_df(myList, ~map_chr(attributes(.x), toString))

#  names                      type        verified   paymentDate startDate  endDate   
#  <chr>                      <chr>       <chr>      <chr>       <chr>      <chr>     
#1 Address                    Residential Unverified NA          NA         NA        
#2 paymentAmount, paymentInfo NA          NA         2021-03-22  2021-02-16 2021-03-15

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM