JPV
JPV

Reputation: 323

Replace column in a list of lists of dataframes with columns in another list of lists of dataframes. R

I have two sets of lists with the following format:

   list(list(structure(list(X = c(3L, 4L, 5L, 7L, 2L, 8L, 9L, 6L, 
    10L, 1L), Y = structure(c(2L, 2L, 1L, 2L, 1L, 2L, 1L, 1L, 2L, 
    1L), .Label = c("no", "yes"), class = "factor")), .Names = c("X", 
    "Y"), row.names = c(NA, -10L), class = "data.frame"), structure(list(
        X = c(3L, 4L, 5L, 7L, 2L, 8L, 9L, 6L, 10L, 1L), Y = structure(c(2L, 
        2L, 1L, 2L, 1L, 2L, 1L, 1L, 2L, 1L), .Label = c("no", "yes"
        ), class = "factor")), .Names = c("X", "Y"), row.names = c(NA, 
    -10L), class = "data.frame")))

and

    list(list(structure(list(X = c(10L, 3L, 4L, 9L, 8L, 2L, 5L, 7L, 
1L, 6L), Y = structure(c(2L, 1L, 2L, 2L, 2L, 1L, 1L, 2L, 1L, 
1L), .Label = c("no", "yes"), class = "factor")), .Names = c("X", 
"Y"), row.names = c(NA, -10L), class = "data.frame"), structure(list(
    X = c(5L, 7L, 4L, 3L, 10L, 2L, 9L, 1L, 8L, 6L), Y = structure(c(2L, 
    2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L), .Label = c("no", "yes"
    ), class = "factor")), .Names = c("X", "Y"), row.names = c(NA, 
-10L), class = "data.frame")))

My objective is to replace a[[1]][[i]]$x <- b[[1]][[i]]$x

This is fairly simple when two dataframes are outside lists:

df1$x<-df2$x

However with the code I wrote it does not work

replacex<-function(onelist, anotherlist){

newlist<-list() #for storage
onelist$x<-anotherlist$x
newlist<-onelist 
}


Dfs_new_X<-lapply(a,lapply,replacex,anotherlist=b)

It does not give an error, but it deletes the column instead.

Any help would be appreciated.

Upvotes: 3

Views: 436

Answers (2)

tc90kk
tc90kk

Reputation: 100

What first puzzled me is that your example lists contain an unnecessary layer. Directly reading in your lists and calling them list_1 and list_2 gives you:

  • list_1 (contains)> list of length one (contains)> two dataframes
  • list_2 (contains)> list of length one (contains)> two dataframes

However, a more common usecase might be the following:

  • list_1 (contains)> two dataframes
  • list_2 (contains)> two dataframes

Since there is no indication that the layer I described as "list of length one" is necessary for your example, I removed it using

list_1 <- list_1[[1]]
list_2 <- list_2[[1]]

Then, you can spare the double application of map2 and simply use mutate from the dplyr package

purrr::map2(list_1, list_2, function(l1, l2){
  dplyr::mutate(l1, X = l2$X)
})

Upvotes: 0

www
www

Reputation: 39174

We can use map2 from the purrr package to conduct this replacement. dat is the final output.

library(purrr)

dat <- map2(a, b, function(x, y){
  map2(x, y, function(i, j){
    i[["X"]] <- j[["X"]]
    return(i)
  })
})

dat
# [[1]]
# [[1]][[1]]
#     X   Y
# 1  10 yes
# 2   3 yes
# 3   4  no
# 4   9 yes
# 5   8  no
# 6   2 yes
# 7   5  no
# 8   7  no
# 9   1 yes
# 10  6  no
# 
# [[1]][[2]]
#     X   Y
# 1   5 yes
# 2   7 yes
# 3   4  no
# 4   3 yes
# 5  10  no
# 6   2 yes
# 7   9  no
# 8   1  no
# 9   8 yes
# 10  6  no

We can also use mapply following the same logic. It generates the same results as the map2 solution.

dat2 <- mapply(function(x, y){
  mapply(function(i, j){
    i[["X"]] <- j[["X"]]
    return(i)
  }, x, y, SIMPLIFY = FALSE)
}, a, b, SIMPLIFY = FALSE)

identical(dat, dat2)
# [1] TRUE

Upvotes: 2

Related Questions