Home > front end >  Apply function on multiple lists in R
Apply function on multiple lists in R

Time:09-08

I have four lists each with multiple data frames.

I need to apply the same function on the lists.

How can I do this?

Sample data:

df1 <- data.frame(x = 1:3, y = letters[1:3])
df2 <- data.frame(x = 4:6, y = letters[4:6])
df3 <- data.frame(x = 7:9, y = letters[7:9])
df4 <- data.frame(x = 10:12, y = letters[10:12])
list1 <- list(df1,df2)
list2 <- list(df3,df4)

In my real data I import based on a pattern in the filename and thus my list elements will have the following names (sample data):

names(list1) <- c("./1. Data/df1.csv", "./1. Data/df2.csv")
names(list2) <- c("./1. Data/df3.csv", "./1. Data/df4.csv")    

And this is one of the functions I want to run on all lists.

element.name <- function(x) {
  
      all_filenames <- names(x) %>% 
      basename() %>% 
      as.list()

      names(x) <- all_filenames

      names(x) <- gsub("\\.csv", "", names(x))
    }

which will give the desired output

names(list1) <- element.name(list1)
names(list1)
[1] "df1"  [2] "df2"

I've tried using a for loop but I end up overwriting my output, so I hope some of you can help me out, since I need to run a lot of functions on my lists.

CodePudding user response:

You could create a list of your lists, and then use lapply to apply to every list the function element.name. You can use setNames to avoid problems linked the assignment on names. You can then use list2env to get your data.frames back to the global environment.

setNames(list(list1, list2), c('list1', 'list2')) |>
  lapply(function(x) setNames(x, element.name(x))) |>
  list2env()

output

> list1
$df1
  x y
1 1 a
2 2 b
3 3 c

$df2
  x y
1 4 d
2 5 e
3 6 f

> list2
$df3
  x y
1 7 g
2 8 h
3 9 i

$df4
   x y
1 10 j
2 11 k
3 12 l

CodePudding user response:

Here is an approach using data.table::fread

library(data.table)

# create dummy CSVs -------------------------------------------------------
DT1 <- data.frame(x = 1:3, y = letters[1:3])
DT2 <- data.frame(x = 4:6, y = letters[4:6])
DT3 <- data.frame(x = 7:9, y = letters[7:9])
DT4 <- data.frame(x = 10:12, y = letters[10:12])

mapply(write.csv, x = list(DT1, DT2, DT3, DT4), file = list("DT1.csv", "DT2.csv", "DT3.csv", "DT4.csv"), row.names = FALSE)

# read in CSVs ------------------------------------------------------------
csv_paths <- list.files(path = ".", pattern = ".csv$")

# might need to split this into different steps due to different csv formats?
DT_list <- setNames(lapply(csv_paths, fread), tools::file_path_sans_ext(basename(csv_paths)))

# apply a function to each data.table -------------------------------------
lapply(DT_list, function(DT){DT[, test := x*2]})

If you want to stick with the given dummy data just merge the lists:

list1 <- list(df1,df2)
list2 <- list(df3,df4)
DT_list <- setNames(c(list1, list2), tools::file_path_sans_ext(basename(csv_paths)))
  • Related