问题
Suppose I'm subsetting from a list of named data.frames with respect to a subsetting variable called long.
After subsetting, some data.frames in the list may be empty because there is no match for subsetting in them.
I was wondering how I could delete all such empty data.frames in my final output.
A simple example, and my unsuccessful solution are shown below:
b <- list(Study1 = data.frame(d = 6:8, long = c(F, F,F)), Study2 = data.frame(d = 9:11, long = c(T, T, F)) )
( h <- lapply(b, subset, subset = long) ) ## subset with respect to "long"
## OUTPUT:
$Study1
[1] d long
<0 rows> (or 0-length row.names) ## This data.frame is empty!! must be deleted ##!
$Study2
d long
1 9 TRUE
2 10 TRUE
## I tried the following with no success: ##
for(i in 1:2) if(nrow(h[[i]]) == 0) h[[i]] <- NULL else h[[i]]
回答1:
Simply Filter by number of rows:
new_list_of_dfs <- Filter(NROW, list_of_dfs)
回答2:
We can use keep
library(purrr)
keep(h, ~ nrow(.x) > 0)
#$Study2
# d long
#1 9 TRUE
#2 10 TRUE
Or use sapply from base R to create a logical condition and Extract the list elements
h[sapply(h, nrow) > 0]
回答3:
The answer by akrun works but to understand why your last line of code didn't work (for(i in 1:2) if(nrow(h[[i]]) == 0) h[[i]] <- NULL else h[[i]]): this is because you're deleting an element of your list before the loop can finish. So, save your query in an index first, and then use the results of that query to delete the elements in a second line. More verbose but more learning for you:
index <- vector(mode = 'logical', length = length(h)) #initialize index as all FALSE
for (i in 1:length(h)) { #this is your last line of code, modified
if(nrow(h[[i]]) != 0) {
index[i] <- TRUE
} else {next}
}
h <- h[index]
来源:https://stackoverflow.com/questions/56081139/how-to-delete-empty-data-frame-in-a-list-after-subsetting-in-r