Home > Mobile >  Adding a new column to a list of data frames and then 'unlist' with names intact?
Adding a new column to a list of data frames and then 'unlist' with names intact?

Time:02-13

I have a number of dfs to which I want to add a column. For the sake of a mrp, these dfs are called df_1, df_2, df_3...

for (i in 1:10) {
assign(paste("df_",i,sep = ""),data.frame(x = rep(1,10), y  = rep(2,10)))
}

I want to add another column z to each of these dfs.

z <- rep("hello",10)

How can I accomplish this?

Using lapply I have been able to do this

q <- list()
for (i in 1:10) {
q[[i]] <-  assign(paste("df_",i,sep = ""),data.frame(x = rep(1,10), y  = rep(2,10)))
}
z <- rep("hello",10)
q <- lapply(q, cbind,z)

This adds the required column, however, I don't know how to preserve the names. How can I still have df_1, df_2, etc but each with a new column z?

Thanks in advance

CodePudding user response:

Using `[<-`().

q <- lapply(q,`[<-`, 'z', value=rep("hello", 10))

Gives

str(q)
# List of 10
# $ :'data.frame':  10 obs. of  3 variables:
#  ..$ x: num [1:10] 1 1 1 1 1 1 1 1 1 1
#  ..$ y: num [1:10] 2 2 2 2 2 2 2 2 2 2
#  ..$ z: chr [1:10] "hello" "hello" "hello" "hello" ...
# $ :'data.frame':  10 obs. of  3 variables:
#  ..$ x: num [1:10] 1 1 1 1 1 1 1 1 1 1
#  ..$ y: num [1:10] 2 2 2 2 2 2 2 2 2 2
#  ..$ z: chr [1:10] "hello" "hello" "hello" "hello" ...
# ...

This works, because `[<-`(df_1, 'z', value=z) is similar to df_1[['z']] <- z. (Actually we're using base:::`[<-.data.frame()`.)

Note: You might get q a little cheaper using replicate:

n <- 3
q <- replicate(n, data.frame(x=rep(1, 3), y=rep(2, 3)), simplify=FALSE) |>
  setNames(paste0('df_', 1:n))
q
# $df_1
#   x y
# 1 1 2
# 2 1 2
# 3 1 2
# 
# $df_2
#   x y
# 1 1 2
# 2 1 2
# 3 1 2
# 
# $df_3
#   x y
# 1 1 2
# 2 1 2
# 3 1 2

CodePudding user response:

Alternatively, you can slightly adjust your own list-method such that the names of the data frames are also stored:

q <- list()
for (i in 1:10) {
  q[[paste0('df_', i)]] <-  data.frame(x = rep(1,10), y  = rep(2,10))
}
z <- rep("hello",10)
q <- lapply(q, cbind,z)

Edit: using list2env mentioned by @jay.sf, the dfs are returned to the global environment.

list2env(q , .GlobalEnv)

CodePudding user response:

Functionally the same as @jay.sf's answer, slightly more verbose/more lines of code, but perhaps easier to understand using transform().

# create dataframes
for (i in 1:10) {
  assign(paste("df_",i,sep = ""),data.frame(x = rep(1,10), y  = rep(2,10)))
}

# store dataframes into a list (only objects starting with df_)
df_list <- mget(ls(pattern="^df_"))

# add new column to each dataframe
lapply(df_list, \(x) transform(x, z = rep("hello", 10)))
  • Related