Skip to content

Instantly share code, notes, and snippets.

@aammd
Last active March 26, 2024 23:31
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save aammd/9ae2f5cce9afd799bafb to your computer and use it in GitHub Desktop.
Save aammd/9ae2f5cce9afd799bafb to your computer and use it in GitHub Desktop.
turning a named list into a dataframe using dplyr

Is there an easy way to convert a named list into a dataframe, preserving the elements of the list in a "list-column"?

    library(dplyr)
    library(magrittr)

    ## make a random matrix
    rand_mat <- function() {
      Nrow <- sample(2:15,1)
      Ncol <- sample(2:15,1)
      rpois(Nrow*Ncol,20) %>%
        matrix(nrow = Nrow,ncol = Ncol)
      }

    ## make a named list
    unnamed.list <- replicate(10,rand_mat(),simplify = FALSE) 

    named.list <- unnamed.list %>% set_names(LETTERS[1:10])

    list_to_df <- function(listfordf){
      if(!is.list(listfordf)) stop("it should be a list")
      
      if(listfordf %>% names %>% is.null) {
        seq_along(listfordf) %>%
          data.frame(matname = ., stringsAsFactors = FALSE) %>%
          rowwise %>%
          do(list.element = listfordf %>% extract2(.$matname))
        } else {
          names(listfordf) %>%
            data.frame(matname = ., stringsAsFactors = FALSE) %>%
            group_by(matname) %>%
            do(comm.matrix = listfordf %>% extract2(.$matname))
          }
    }

    list_to_df(unnamed.list)

    ## Source: local data frame [10 x 1]
    ## Groups: <by row>
    ## 
    ##    list.element
    ## 1   <int[7,11]>
    ## 2  <int[15,14]>
    ## 3    <int[6,4]>
    ## 4  <int[11,14]>
    ## 5   <int[2,10]>
    ## 6  <int[11,13]>
    ## 7  <int[11,11]>
    ## 8   <int[13,8]>
    ## 9   <int[11,5]>
    ## 10  <int[4,15]>

    list_to_df(named.list)

    ## Source: local data frame [10 x 1]
    ## Groups: <by row>
    ## 
    ##    list.element
    ## 1   <int[7,11]>
    ## 2  <int[15,14]>
    ## 3    <int[6,4]>
    ## 4  <int[11,14]>
    ## 5   <int[2,10]>
    ## 6  <int[11,13]>
    ## 7  <int[11,11]>
    ## 8   <int[13,8]>
    ## 9   <int[11,5]>
    ## 10  <int[4,15]>

The dplyr package is used to apply the "Split-Apply-Combine" method of data analysis. Many useRs might have previously used named lists in combination with plyr::llply or plyr::ldply, applying a function to each section before combining them.

@austinj
Copy link

austinj commented Dec 20, 2017

I'm very late to the party, but I think that the second line of the list_to_df function Hadley wrote above should name the argument as listfordf, not named.list.

@EvanFalcone
Copy link

^ confirming. It's no biggy, the input variable name probably just changed midway or something.

@dsolito
Copy link

dsolito commented Feb 17, 2019

Hello, I had the same problem.
Finally, I resolved it with :

list(site1 = c("url1", "url2"), site2 = c("url2", "url3", "url3")) %>% 
  enframe() %>% 
  unnest()

@Tayflo
Copy link

Tayflo commented Jan 5, 2021

Hello, I had the same problem.
Finally, I resolved it with :

list(site1 = c("url1", "url2"), site2 = c("url2", "url3", "url3")) %>% 
  enframe() %>% 
  unnest()

Very nice, thanks! I needed this to properly use a JSON file imported from jsonlite.

If it can be of use to anyone, here is a full reprex of the above code (with some details):

library(magrittr)
list(
  site1 = c("url1", "url2"),
  site2 = c("url2", "url3", "url3")
) %>%
  tibble::enframe("site", "url") %>%
  tidyr::unnest(cols = url)
#> # A tibble: 5 x 2
#>   site  url  
#>   <chr> <chr>
#> 1 site1 url1 
#> 2 site1 url2 
#> 3 site2 url2 
#> 4 site2 url3 
#> 5 site2 url3

Created on 2021-01-05 by the reprex package (v0.3.0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment