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)))