2

Although the title looks easy, I have not found an answer here on StackOverflow. My problem is: I have a list of some elements. And each elemnt of the list also contains a list filled with some strings. That list inside list contains values that are empty (''), not null. I would like to remove the rows inside that list that are empty. How one can do it? I guess lapply would do the trick but I am not sure how to use it there.

Would be grateful for an advice! Thanks a lot!

EDIT: So my output looks like this

$'1' 1 text1 2 text2 3 4 text3 5 text4 $'2' 1 text1 2 3 text2 4 5 text3 

My goal is to delete those rows that are empty so that it looked like this:

$'1' 1 text1 2 text2 3 text3 4 text4 $'2' 1 text1 2 text2 3 text3 
0

2 Answers 2

7

You're correct in that you can use lapply here.

test <- list(c("text1", "text2", "", "text3", "text4"), c("text1", "", "text2", "", "text3")) lapply(1:length(test), function(x) test[[x]][test[[x]] != ""]) [[1]] [1] "text1" "text2" "text3" "text4" [[2]] [1] "text1" "text2" "text3" 
Sign up to request clarification or add additional context in comments.

Comments

0

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" ## ## 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.