Reputation: 185
I have a list of list of lists in R. I want to remove the ones that are of length zero.
What I have tried so far is:
for (i in 1:length(test)) {
keep <- rep(T, length(test))
for (j in 1:length(test[[i]])) {
if (length(test[[i]][[j]]) == 0) {
keep[[j]] <- F
}
}
test2[i] <- test2[i][keep]
}
Here is some example data (edited):
test <- list("Section 1" = list("A" = list(), "B" = list("1x1" = "23", "1x2" = "24"), C = list("2x1" = "78")),
"Section 2" = list("A" = list(), "B" = list("1x1" = "23", "1x2" = "24"), C = list("2x1" = "78")))
I would like a way to remove the "A" list in both section 1 and section 2 since both are length 0
Upvotes: 3
Views: 1446
Reputation: 79238
You can just write your own function:
check = function(x){
m = lengths(x)>0
if(is.list(x[m])) lapply(x[m],check) else x
}
check(test)
$`Section 1`
$`Section 1`$`B`
$`Section 1`$`B`$`1x1`
[1] "23"
$`Section 1`$`B`$`1x2`
[1] "24"
$`Section 1`$C
$`Section 1`$C$`2x1`
[1] "78"
$`Section 2`
$`Section 2`$`B`
$`Section 2`$`B`$`1x1`
[1] "23"
$`Section 2`$`B`$`1x2`
[1] "24"
$`Section 2`$C
$`Section 2`$C$`2x1`
[1] "78"
Upvotes: 1
Reputation: 50678
Just to wrap things up, and as per my earlier comment you can do
Filter(function(x) length(x) > 0, test)
#$B
#$B$`1x1`
#[1] "23"
#
#$B$`1x2`
#[1] "24"
#
#
#$C
#$C$`2x1`
#[1] "78"
or shorter still (thanks @Parfait)
Filter(length, test)
For a nested list
test <- list("Section 1" = list("A" = list(), "B" = list("1x1" = "23", "1x2" = "24"), C = list("2x1" = "78")), "Section 2" = list("A" = list(), "B" = list("1x1" = "23", "1x2" = "24"), C = list("2x1" = "78")))
lapply(test, function(x) Filter(length, x))
#$`Section 1`
#$`Section 1`$B
#$`Section 1`$B$`1x1`
#[1] "23"
#
#$`Section 1`$B$`1x2`
#[1] "24"
#
#
#$`Section 1`$C
#$`Section 1`$C$`2x1`
#[1] "78"
#
#
#
#$`Section 2`
#$`Section 2`$B
#$`Section 2`$B$`1x1`
#[1] "23"
#
#$`Section 2`$B$`1x2`
#[1] "24"
#
#
#$`Section 2`$C
#$`Section 2`$C$`2x1`
#[1] "78"
Upvotes: 2
Reputation: 263382
Claiming this is a duplicate requires the additional knowledge that lists containing only NULL items have length 0. Also requires assuming that NULL
and list()
are equivalent. Neither of those are necessarily obvious, although testing that proposition with sapply(list(a=NULL), length)
shows the first to be the case. The second however appears not the case. Test: identical(NULL, list())
returns FALSE, as do identical(list(NULL), list())
and is.null( list() )
.
The answer from Maurits Evers should succeed. This will also succeed:
test <- test[ sapply(test, length) >0] # `sapply will return a logical vector
> test
$B
$B$`1x1`
[1] "23"
$B$`1x2`
[1] "24"
$C
$C$`2x1`
[1] "78"
Upvotes: 0