18

Seems like a basic question and perhaps I'm just missing something obvious ... but is there any way to pluck a sublist (with purrr)? More specifically, here's an initial list:

l <- list(a = "foo", b = "bar", c = "baz")

And I want to return a new (sub-)list with only elements a and b. Normally, I'd just do 'base' R sub-listing:

l[c("a", "b")]

But this doesn't provide the nice .default handling of pluck. My understanding is that pluck 'replaces' [[, but is there a purrr equivalent for replacing [?

mmuurr
  • 1,310
  • 1
  • 11
  • 21
  • 2
    I don't think a direct 'replacement' for `[` exists, at least not in `purrr`. I guess a workaround would be `map(set_names(c("a", "b", "z")), partial(pluck, l), .default = "Not found!")` but that's not very neat! – Mikko Marttila Oct 28 '17 at 08:35

4 Answers4

8

Similar to jzadra's post, you could also do:

l %>% keep(names(.) %in% c("a","b"))
Arjun Baghela
  • 81
  • 1
  • 3
7

Here's my take on it. Not based on purrr thus slightly off topic, but compatible with the tidyverse's general interface principle of playing nicely with pipes.

pluck_multiple <- function(x, ...) {
  `[`(x, ...)
}

x <- list(a = 1, b = 2, c = list(x = TRUE, y = FALSE))

pluck_multiple(x, c("a", "b"))
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
pluck_multiple(x, 2:3)
#> $b
#> [1] 2
#> 
#> $c
#> $c$x
#> [1] TRUE
#> 
#> $c$y
#> [1] FALSE
Rappster
  • 12,762
  • 7
  • 71
  • 120
2

There's clearly a need for "muti-value pluck". It really comes down to extending flexibility of "pluck" to retrieving multiple values from the same level of list, as described in this github issue. For the example above, you can probably get away with:

> purrr::map(purrr::set_names(c("a", "b")), 
          ~purrr::pluck(l, .x, .default = NA_character_))
#> $a
#> [1] "foo"
#> 
#> $b
#> [1] "bar"
dmi3kno
  • 2,943
  • 17
  • 31
1

I think that purrr::keep() does what you want.

l %>% keep(names(.) == "a" | names(.) == "b")

jzadra
  • 4,012
  • 2
  • 26
  • 46