问题
Suppose I'm subsetting from a list
of named data.frame
s with respect to a subsetting variable called long
.
After subsetting, some data.frame
s 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.frame
s 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