This is a surprisingly tough problem. First I synthesized some test data:
l <- list(list('a','b','','c','','d'),list('','e','')); l; ## [[1]] ## [[1]][[1]] ## [1] "a" ## ## [[1]][[2]] ## [1] "b" ## ## [[1]][[3]] ## [1] "" ## ## [[1]][[4]] ## [1] "c" ## ## [[1]][[5]] ## [1] "" ## ## [[1]][[6]] ## [1] "d" ## ## ## [[2]] ## [[2]][[1]] ## [1] "" ## ## [[2]][[2]] ## [1] "e" ## ## [[2]][[3]] ## [1] "" ## ##
Here's my solution:
matches <- do.call(rbind,lapply(seq_along(l),function(li) cbind(li,which(do.call(c,l[[li]])=='')))); matches; ## li ## [1,] 1 3 ## [2,] 1 5 ## [3,] 2 1 ## [4,] 2 3 invisible(apply(matches[rev(seq_len(nrow(matches))),],1,function(lri) l[[lri]] <<- NULL)); l; ## [[1]] ## [[1]][[1]] ## [1] "a" ## ## [[1]][[2]] ## [1] "b" ## ## [[1]][[3]] ## [1] "c" ## ## [[1]][[4]] ## [1] "d" ## ## ## [[2]] ## [[2]][[1]] ## [1] "e" ## ##
This uses recursive list indexing. This type of indexing is documented in Extract or Replace Parts of an Object:
[[ can be applied recursively to lists, so that if the single index i is a vector of length p, alist[[i]] is equivalent to alist[[i1]]...[[ip]] providing all but the final indexing results in a list.
This solution also leverages the fact that assigning NULL to a list component deletes that component. From the same documentation page:
Note that in all three kinds of replacement, a value of NULL deletes the corresponding item of the list. To set entries to NULL, you need x[i] <- list(NULL).
It was also important to delete components with higher indexes first; otherwise the precomputed higher indexes would be invalidated by the deletion of lower indexes. Hence I ran apply() over matches[rev(seq_len(nrow(matches))),] instead of matches.
Actually there's another easier way which involves rebuilding the list, omitting undesired elements:
lapply(l,function(l2) l2[do.call(c,l2)!='']) ## [[1]] ## [[1]][[1]] ## [1] "a" ## ## [[1]][[2]] ## [1] "b" ## ## [[1]][[3]] ## [1] "c" ## ## [[1]][[4]] ## [1] "d" ## ## ## [[2]] ## [[2]][[1]] ## [1] "e" ## ##