2

I have a multiple lists in my environment(all start with "CDS_"). Each list is conducted of multiple sub lists.I want to call the lists one by one to apply a function for each of these objects. This is what I am trying:

lists<-grep("CDS_",names(.GlobalEnv),value=TRUE) #Lists all objectrs staring with "CDS_" for (i in seq_along(lists)){ data<-do.call("list",mget(lists[i])) #this line blends all sub lists into one list assign(paste("Df_", lists[i], sep = "_"), my_function(data) # my_function requires a list with multiple sub lists } 

but the issue is the do.call("list",mget(lists[i])) blends all sub lists into one. For example if there is a list with one sub list it returns the list but all sub lists go into one!

Any solutions how to make this work?

here is a sample to test:

#Defining my_function pulling out the sub list which contains "sample1" my_function<-function(.data){ # pull out the undergraduate data grep("sample1", .data, value = TRUE) } # 1st list list_1 <- list(1:54, c("This","is","sample1","for","list1"), c("This","is","sample2","for","list1"), "Hi") # 2nd list list_2 <- list(51:120, c("This","is","sample1","for","list1"), c("This","is","sample2","for","list1"), "Bus") # 3rd list list_3 <- list(90:120, letters[16:11], 2025) lists<-grep("list_",names(.GlobalEnv),value=TRUE) for (i in seq_along(lists)){ data<-do.call("list",mget(lists[i])) assign(paste("sample1_", lists[i], sep = ""), my_function(data)) } 
2
  • 3
    It's easier to help you if you provide a reproducible example with sample input and desired output that can be used to test and verify possible solutions. It's not clear why you need the do.call here. You seem to be calling mget() with only value value at a time. Messing with mget and assign is often a messy alternative to just sticking with a list. Commented May 13, 2022 at 17:56
  • @MrFlick added the sample code Commented May 13, 2022 at 18:40

2 Answers 2

4

As mentioned by @MrFlick, R has a ton of list functionality. It is usually the case that you are better off storing your lists in a list than trying to directly edit them in the environment. Here is one possible solution using base R:

l <- mget(ls(pattern = "^list_\\d$")) # store lists in a list lapply(l, \(x) lapply(x, my_function)) $list_1 $list_1[[1]] character(0) $list_1[[2]] [1] "sample1" $list_1[[3]] character(0) $list_1[[4]] character(0) $list_2 $list_2[[1]] character(0) $list_2[[2]] [1] "sample1" $list_2[[3]] character(0) $list_2[[4]] character(0) $list_3 $list_3[[1]] character(0) $list_3[[2]] character(0) $list_3[[3]] character(0) 

Update

Sticking with base R to remove non-matches you could do:

lapply(l, \(x) Filter(length, lapply(x, my_function))) $list_1 $list_1[[1]] [1] "sample1" $list_2 $list_2[[1]] [1] "sample1" $list_3 list() 

A purrr solution would be:

library(purrr) map(map_depth(l, 2, my_function), compact) 
Sign up to request clarification or add additional context in comments.

3 Comments

Great answer! Nice to see a new voice competently addressing list-related questions!
Thanks for the suggestion @LMc, what if I want to pull out only the sub list that qualifies from each list and put them all in another list(each in a separate sub list)?
@Hossein you are welcome, I have updated my post with a possible solution.
3

When you have lists of lists, and option is rapply, the recursive version of lapply.

my_function<-function(.data){ # pull out the undergraduate data grep("sample1", .data, value = TRUE) } lists <- mget(ls(pattern = "^list_")) rapply(lists, my_function, how = "list") #> $list_1 #> $list_1[[1]] #> character(0) #> #> $list_1[[2]] #> [1] "sample1" #> #> $list_1[[3]] #> character(0) #> #> $list_1[[4]] #> character(0) #> #> #> $list_2 #> $list_2[[1]] #> character(0) #> #> $list_2[[2]] #> [1] "sample1" #> #> $list_2[[3]] #> character(0) #> #> $list_2[[4]] #> character(0) #> #> #> $list_3 #> $list_3[[1]] #> character(0) #> #> $list_3[[2]] #> character(0) #> #> $list_3[[3]] #> character(0) 

Created on 2022-05-13 by the reprex package (v2.0.1)


Edit

To answer to the OP's comment to another answer, to keep only the matches, save the rapply result and a lapply loop calling lengths, the list version of vector length is used to extract the matches.

r <- rapply(lists, my_function, how = "list") lapply(r, \(x) x[lengths(x) > 0]) #> $list_1 #> $list_1[[1]] #> [1] "sample1" #> #> #> $list_2 #> $list_2[[1]] #> [1] "sample1" #> #> #> $list_3 #> list() 

Created on 2022-05-13 by the reprex package (v2.0.1)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.