6

Suppose there is a list as follows:

x <- list(a = list(a1 = 1, a2 = 2), b = list(a2 = 3, a1 = 4))

The positions/names are mixed in the sublists, and to pluck out the a1s from the list, I would do the following in purrr.

x %>% map(purrr::pluck, "a1")
$`a`
[1] 1

$b
[1] 4

To throw out an element instead of keeping it, I experimented a bit, and came up with the following (I threw out a2 here).

x %>% map(purrr::assign_in, "a2", value = NULL)
$`a`
$`a`$`a1`
[1] 1


$b
$b$`a1`
[1] 4

In terms of plucking, I actually like the second style better---that is, to keep the list indexing structure as is, while returning only the elements that I want. So I would prefer that once I perform x %>% map(purrr::pluck, "a1"), I get the second result.

Alternatively maybe there is a better way of throwing objects out in purrr that I'm not aware of, so that the output styles of the two code (plucking, throwing away) would be consistent?

Kim
  • 4,080
  • 2
  • 30
  • 51

2 Answers2

4

If we need a consistent approach, use keep

library(purrr)
map(x, ~ keep(.x, names(.x) == "a1"))
#$a
#$a$a1
#[1] 1


#$b
#$b$a1
#[1] 4

and discard

map(x, ~ discard(.x, names(.x) == "a1"))
#$a
#$a$a2
#[1] 2


#$b
#$b$a2
#[1] 3
akrun
  • 874,273
  • 37
  • 540
  • 662
0

Here's another way using modify_at, and proposing a more idiomatic way to do your first call :

library(purrr)
#> Warning: package 'purrr' was built under R version 3.5.3
x <- list(a = list(a1 = 1, a2 = 2), b = list(a2 = 3, a1 = 4))

# rather than x %>% map(purrr::pluck, "a1")
x %>% map("a1")
#> $a
#> [1] 1
#> 
#> $b
#> [1] 4
x %>% modify(modify_at,"a2", ~NULL)
#> $a
#> $a$a1
#> [1] 1
#> 
#> 
#> $b
#> $b$a1
#> [1] 4

Created on 2019-05-05 by the reprex package (v0.2.1)

moodymudskipper
  • 46,417
  • 11
  • 121
  • 167