Search code examples
rlistsubsetvectorization

How to subset items in a list


Consider.

li <- list(c(1,1,1), c(2,1,1), c(5,1,0))
## [[1]]
## [1] 1 1 1                <-- 0 modulo 3
## 
## [[2]]
## [1] 2 1 1
## 
## [[3]]
## [1] 5 1 0                <--- 0 modulo 3

I want to keep all items in the list whose sum modulo 3 equals zero (or some other logical expression regarding the item in the list).

Code.

  new <- list()
  idx <- 1
  for (i in seq_along(li) ) {
    nxt <- li[[i]]
    if ((sum(nxt) %% 3) == 0) {
      new[idx] <- list(nxt)
      idx <- idx + 1
    } 
  }
## new
## [[1]]
## [1] 1 1 1
##
## [[2]]
## [1] 5 1 0

However. I would like a vectorized solution. I tried.

new <- subset(li, lapply(li, (sum %% 3) == 0 ))

but to no avail.

Edit See also Difference between subset and filter from dplyr for more detailed information.


Solution

  • in Base R:

    Filter(\(x)!sum(x)%%3, li)
    [[1]]
    [1] 1 1 1
    
    [[2]]
    [1] 5 1 0
    

    in tidyverse

    purrr::keep(li, ~!sum(.x)%%3)
    [[1]]
    [1] 1 1 1
    
    [[2]]
    [1] 5 1 0
    
    purrr::discard(li, ~!!sum(.x)%%3) # !0
    [[1]]
    [1] 1 1 1
    
    [[2]]
    [1] 5 1 0