I never use list-columns but it seems to me that x is still a list when used inside the mutate and you want %in% to compare the first element of x to c(2,3).
library(tibble)
library(dplyr)
DF <- tibble(x = list(c(1, 2, 3)))
DF
#> # A tibble: 1 x 1
#> x
#> <list>
#> 1 <dbl [3]>
DF %>% mutate(matches = x[[1]] %in% c(2, 3) %>% sum())
#> # A tibble: 1 x 2
#> x matches
#> <list> <int>
#> 1 <dbl [3]> 2
But that works because you have hard coded x[[1]]. If DF has 2 rows or more, your code won't work. Or, rather, it will just give us matches = 2 in every row.
library(tibble)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
DF <- tibble(x = list(c(1, 2, 3), c(2, 4, 5)))
DF %>% mutate(matches = x[[1]] %in% c(2, 3) %>% sum())
#> # A tibble: 2 x 2
#> x matches
#> <list> <int>
#> 1 <dbl [3]> 2
#> 2 <dbl [3]> 2
I'm going to take away the sum() and then the tidyverse trappings to try to see what this looks like "under-the-hood" to %in%. The summary point here being that list(c(1, 2, 3)) %in% c(2, 3) returns FALSE, while numeric vector inside that list returns the results for the individual components.
Not sure if this clears things up, but I find it helpful to break things down a bit.
library(tidyverse)
tibble(x = list(c(1, 2, 3))) %>%
mutate(matches = x %in% c(2, 3))
#> # A tibble: 1 x 2
#> x matches
#> <list> <lgl>
#> 1 <dbl [3]> FALSE
list(c(1, 2, 3)) %in% c(2, 3)
#> [1] FALSE
x <- list(c(1, 2, 3))
x %in% c(2, 3)
#> [1] FALSE
y <- x[[1]]
class(x)
#> [1] "list"
class(y)
#> [1] "numeric"
y %in% c(2, 3)
#> [1] FALSE TRUE TRUE
Thanks! I now understand that my confusion has nothing to do with list-columns. Instead, I (mistakenly!) thought that %in% would work the same with lists as it does with vectors. Thanks for showing that it does not.