Search code examples
rlistwrite.table

R: write list of lists of lists to a text file with names


I have a list of lists of lists with this structure:

a = list("t" = list('abc'), "c" = list('def','ghi')) 
b = list("t" = list('jk','kl'), "c" = list('lmn')) 
c = list("t" = list('op','pq','z'), "c" = list('qrs','tuv','wxy'))
ls = list('one'=a,'two'=b,'three'=c)

I need to store this in a text file. Since not all elements are the same length, I need to fill with nans before turning it into a dataframe and writing to a file. I want a file that looks something like this (shown roughly as .csv here, but .txt is fine):

 t1, t2, t3, c1, c2, c3
one,abc,nan,nan,def,ghi,nan
two,jk,kl,nan,lmn,nan,nan
three,op,pq,z,qrs,tuv,wxy

I'm new to R so I only have a general sense of how I might do this and can't figure out the syntax. Something like this in pseudocode:

lapply(ls, fill nans)
lapply(ls, unlist)
lapply(ls, names=[t1,t2,t3,c1,c2,c3])
df=data.frame(ls)
write.table(df)

Can someone walk me through this?

edit: I was able to make some progress with:

ellength <- function(ls,i) {return(length(ls[[i]]))}

fillna <- function(ls,i,m) {
if (length(ls[[i]])<m) {
return(append(ls[[i]],vector('list',length=m-length(ls[[i]]))))
}
else {return(ls[[i]])}
}

make_col <- function(ls,i){
return(lapply(ls,fillna,i=i,m=max(unlist(lapply(ls,ellength,i=i)))))
}

> matrix(list(make_col(ls,'t'),make_col(ls,'c')))
     [,1]  
[1,] List,3
[2,] List,3

But I still can't write this to a file in any coherent way. This is so simple to do in Python; I must be missing something. Help?


Solution

  • Does this help at all?

    library(tidyr)
    library(dplyr)
    a = list("t" = 'abc', "c" = list('def','ghi')) 
    b = list("t" = 'jk', "c" = list('lmn')) 
    c = list("t" = 'op', "c" = list('qrs','tuv','wxy'))
    ls = list('one'=a,'two'=b,'three'=c)
    #unlist and turn into a df
    lx <- as.data.frame( unlist(ls),stringsAsFactors = FALSE)
    #make rownames as column
    lx$nms <- rownames(lx)
    
    #split nms column so you can transpose your data
    lx <- separate(lx, nms, c("v1","v2"), sep = "[.]")
    lx <- mutate(lx, v3 = `unlist(ls)`) %>% 
          select(-`unlist(ls)`)
    #transpose your data - it fills with NA
    #NaN is a numeric field so you can't use it to fill character variables
    lx2 <- spread(lx,v2,v3)
    

    update

    If you want to collapse over variables you can use ifelse to replace NAs in certain columns:

    lx2 <- mutate(lx2, c_1 = ifelse(is.na(c),c1,c))
    lx2 <- mutate(lx2, t_1 = ifelse(is.na(t),t1,t))
    lx3 <- lx2[c('v1','c_1','c2','c3','t_1','t2','t3')]