user10256905
user10256905

Reputation: 185

Removing nested lists of length 0

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

Answers (3)

Onyambu
Onyambu

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

Maurits Evers
Maurits Evers

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

IRTFM
IRTFM

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

Related Questions