7

I have a dataframe that I want to convert to a nested list with a custom level of nesting. This is how I do it, but I'm sure there is a better way:

data <- data.frame(city=c("A", "A", "B", "B"), street=c("a", "b", "a", "b"), tenant=c("Smith","Jones","Smith","Jones"), income=c(100,200,300,400))

nested_data <- lapply(levels(data$city), function(city){
    data_city <- subset(data[data$city == city, ], select=-city)
    list(city = city, street_values=lapply(levels(data_city$street), function(street){
        data_city_street <- subset(data_city[data_city$street == street, ], select=-street)
        tenant_values <- apply(data_city_street, 1, function(income_tenant){
            income_tenant <- as.list(income_tenant)
            list(tenant=income_tenant$tenant, income=income_tenant$income)
        })
        names(tenant_values) <- NULL
        list(street=street, tenant_values=tenant_values)
    }))
})

The output in JSON looks like:

library(rjson)
write(toJSON(nested_data), "")
[{"city":"A","street_values":[{"street":"a","tenant_values":[{"tenant":"Smith","income":"100"}]},{"street":"b","tenant_values":[{"tenant":"Jones","income":"200"}]}]},{"city":"B","street_values":[{"street":"a","tenant_values":[{"tenant":"Smith","income":"300"}]},{"street":"b","tenant_values":[{"tenant":"Jones","income":"400"}]}]}]

# or prettified:

[
  {
    "city": "A",
    "street_values": [
      {
        "street": "a",
        "tenant_values": [
          {
            "tenant": "Smith",
            "income": "100"
          }
        ]
      },
      {
        "street": "b",
        "tenant_values": [
          {
            "tenant": "Jones",
            "income": "200"
          }
        ]
      }
    ]
  },
  {
    "city": "B",
    "street_values": [
      {
        "street": "a",
        "tenant_values": [
          {
            "tenant": "Smith",
            "income": "300"
          }
        ]
      },
      {
        "street": "b",
        "tenant_values": [
          {
            "tenant": "Jones",
            "income": "400"
          }
        ]
      }
    ]
  }
]

Is there a better way to do this?

2
  • So, are you asking a question about JSON output from R, or how to create an R object which is a "nested list" in R's definition, e.g. foo<-list(bar=NA,snafu="hello, Dave"); foo[[bar]] <- list(a=1,b=2) ? Commented Mar 4, 2013 at 16:59
  • I just showed the JSON output because it is easier to understand than the R list format, but I want to go from R dataframe to R list Commented Mar 4, 2013 at 17:30

2 Answers 2

9

What about using split to get you most of the way, and rapply for the last step:

nestedList <- rapply(lapply(split(data[-1], data[1]), 
                            function(x) split(x[-1], x[1])), 
                     f = function(x) as.character(unlist(x)), 
                     how = "replace")

Here's the output:

nestedList
# $A
# $A$a
# $A$a$tenant
# [1] "Smith"
# 
# $A$a$income
# [1] "100"
# 
# 
# $A$b
# $A$b$tenant
# [1] "Jones"
# 
# $A$b$income
# [1] "200"
# 
# 
# 
# $B
# $B$a
# $B$a$tenant
# [1] "Smith"
# 
# $B$a$income
# [1] "300"
# 
# 
# $B$b
# $B$b$tenant
# [1] "Jones"
# 
# $B$b$income
# [1] "400"

And the structure:

> str(nestedList)
List of 2
 $ A:List of 2
  ..$ a:List of 2
  .. ..$ tenant: chr "Smith"
  .. ..$ income: chr "100"
  ..$ b:List of 2
  .. ..$ tenant: chr "Jones"
  .. ..$ income: chr "200"
 $ B:List of 2
  ..$ a:List of 2
  .. ..$ tenant: chr "Smith"
  .. ..$ income: chr "300"
  ..$ b:List of 2
  .. ..$ tenant: chr "Jones"
  .. ..$ income: chr "400"

The structure doesn't exactly match what you're looking for, but this might help get you started with an alternative approach.

Sign up to request clarification or add additional context in comments.

Comments

1

I found the solution of my question by changing the function as:

nestedList <- rapply(lapply(split(df[-1], df[1]),
                          function(x) split(x[-1], x[1])),
                   f = function(x) as.data.frame(as.list(split(x,x))),  how = "replace")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.