How do I filter a list with modify_depth and keep?

purrr

#1

I want to filter a nested list by an attribute at .depth = 2. I can extract the attribute with modify_depth(x, 2, ~attr(.x, "p")), but I do not know how to include a keep clause to filter the desired elements. In other words, how do I keep at .depth = 2?


#2

Never mind–I just flattened the list before keeping, e.g. flatten(x) %>% keep(~attr(.x, "p"))


#3

Example data:

library(purrr)

y <- "foo"
attr(y, "p") <- FALSE
z <- "bar"
attr(z, "p") <- TRUE
x <- list(list(y, z), list(y, y, y), list(z))
str(x)
# List of 3
#  $ :List of 2
#   ..$ : atomic [1:1] foo
#   .. ..- attr(*, "p")= logi FALSE
#   ..$ : atomic [1:1] bar
#   .. ..- attr(*, "p")= logi TRUE
#  $ :List of 3
#   ..$ : atomic [1:1] foo
#   .. ..- attr(*, "p")= logi FALSE
#   ..$ : atomic [1:1] foo
#   .. ..- attr(*, "p")= logi FALSE
#   ..$ : atomic [1:1] foo
#   .. ..- attr(*, "p")= logi FALSE
#  $ :List of 1
#   ..$ : atomic [1:1] bar
#   .. ..- attr(*, "p")= logi TRUE

Your solution:

res_1 <- flatten(x) %>% keep(~attr(.x, "p"))
str(res_1)
# List of 2
#  $ : atomic [1:1] bar
#   ..- attr(*, "p")= logi TRUE
#  $ : atomic [1:1] bar
#   ..- attr(*, "p")= logi TRUE

Alternative solution that keeps the nested structure: to “keep at depth 2”, we simply map (equivalent to “modify at depth 1”) the keep function:

res_2 <- map(x, keep, attr, "p")
str(res_2)
# List of 3
#  $ :List of 1
#   ..$ : atomic [1:1] bar
#   .. ..- attr(*, "p")= logi TRUE
#  $ : list()
#  $ :List of 1
#   ..$ : atomic [1:1] bar
#   .. ..- attr(*, "p")= logi TRUE

#4

That is more elegant, thanks! I forgot to add the filtering criteria to keep, so I think I’d have to go something like this?

res_2 <- map(x, ~keep(., ~attr(., "p") %in% as.character(1:5)))