Add a new column in each table of a list, and fill it with the name of the table

Viewed 40

I have a list of 25 data table, each table has 2 columns. The tables inside the list are named from 1 to 25. I would like to add a column in each table containing in each row just the name of the table, like this:

Table 1

A  B  
x  y  
x  y  
x  y  

Table 2

A  B  
x  y  
x  y  
x  y 

Table 3

A  B  
x  y  
x  y  
x  y 

Table 1 new

A B new column
X Y 1
X Y 1
X Y 1

Table 2 new

A B new column
X Y 2
X Y 2
X Y 2

Table 3 new

A B new column
X Y 3
X Y 3
X Y 3

I know I should use function(x) and then lapply, and I know there are different ways to add a new column. I just don't know how to fill the columns with the numbers.

3 Answers

We could use map2. Here we create first a vector with the number of dataframes in the list in this example 1:3. In your original example 1:25:

library(purrr)

my_list <- list(table1,table2, table3) 
ID <- 1:3

map2(my_list, ID, ~cbind(.x, ID = .y))
[[1]]
  A B ID
1 x y  1
2 x y  1
3 x y  1

[[2]]
  A B ID
1 x y  2
2 x y  2
3 x y  2

[[3]]
  A B ID
1 x y  3
2 x y  3
3 x y  3

How about a simple loop? This is as far as I can see the simplest way to utilize the named structure of your list directly.

# Test data
testlist <- list("1" = data.frame(A = c("x"), B = c("y")),
                 "2" = data.frame(A = c("xx"), B = c("yy")))

# Loop through all names
for (each_table in names(testlist)) {
  
  testlist[[each_table]]$new_col <- each_table
  
}

testlist

Output:

$`1`
  A B new_col
1 x y       1

$`2`
   A  B new_col
1 xx yy       2

A base solution with Map():

Map(cbind, lst, new = seq_along(lst))

You could also use imap() from purrr to bind each data frame and its index of the list.

purrr::imap(lst, ~ cbind(.x, new = .y))
Output
[[1]]
  A B new
1 x y   1
2 x y   1
3 x y   1

[[2]]
  A B new
1 x y   2
2 x y   2
3 x y   2

[[3]]
  A B new
1 x y   3
2 x y   3
3 x y   3
Data
lst <- rep(list(data.frame(A = rep("x", 3), B = rep("y", 3))), 3)
Related