In the first example that does work, . is part of the pipe syntax, so it refers to the list that you piped into purrr::keep().
In the second example, ~ names(.x) %in% c("a", "b") is shorthand for
f <- function(.x) names(.x) %in% c("a", "b")
but when a function is applied to each element of a list, the name of the list element isn't available.
library(purrr)
ex_list <- list('a' = list(1,2),'b'=list(list(3,4), list(5,6)), 'c' = 'hello')
el_name <- function(x) names(x)
map(ex_list, el_name)
#> $a
#> NULL
#>
#> $b
#> NULL
#>
#> $c
#> NULL
The result is NULL for each element because the elements passed to el_name() are nameless.
I believe the easiest way to subset a list by name is to use base R list filtering syntax, i.e. [ ] single bracket subsetting.
ex_list[c("a", "b")]
#> $a
#> $a[[1]]
#> [1] 1
#>
#> $a[[2]]
#> [1] 2
#>
#>
#> $b
#> $b[[1]]
#> $b[[1]][[1]]
#> [1] 3
#>
#> $b[[1]][[2]]
#> [1] 4
#>
#>
#> $b[[2]]
#> $b[[2]][[1]]
#> [1] 5
#>
#> $b[[2]][[2]]
#> [1] 6
Created on 2019-02-26 by the reprex package (v0.2.1)