Consider this simple list
list('a' = list(1,2),'b'=list(list(3,4), list(5,6)), 'c' = 'hello')
$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
$c
[1] "hello"
Let's say I want to keep the element a
and b
from it. I do not understand why this works
list('a' = list(1,2),'b'=list(list(3,4), list(5,6)), 'c' = 'hello') %>%
purrr::keep(names(.) == 'a' | names(.) == 'b')
while using the following does not work
> list('a' = list(1,2),'b'=list(list(3,4), list(5,6)), 'c' = 'hello') %>%
+ purrr::keep(~names(.x) %in% c('a','b'))
Error: Predicate functions must return a single `TRUE` or `FALSE`, not a logical vector of length 0
Call `rlang::last_error()` to see a backtrace
what is wrong with the second syntax?
Thanks!
1 Like
grrrck
February 26, 2019, 8:24pm
2
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)
5 Likes
thanks! but how can I use [
in a pipe then?
grrrck
February 26, 2019, 9:05pm
4
You can write your own "keep" function that does what you want, or you can use dot notation.
library(purrr)
ex_list <- list('a' = list(1,2),'b'=list(list(3,4), list(5,6)), 'c' = 'hello')
keep_by_name <- function(l, keep_names) l[keep_names]
ex_list %>% keep_by_name(c("a", "c"))
#> $a
#> $a[[1]]
#> [1] 1
#>
#> $a[[2]]
#> [1] 2
#>
#>
#> $c
#> [1] "hello"
ex_list %>% .[c("a", "c")]
#> $a
#> $a[[1]]
#> [1] 1
#>
#> $a[[2]]
#> [1] 2
#>
#>
#> $c
#> [1] "hello"
Created on 2019-02-26 by the reprex package (v0.2.1)
This same issue always gets me too -- I always think keep()
should keep top level elements, but it works at the second level of a list rather than the first.
cderv
February 26, 2019, 9:45pm
5
magrittr
have some useful function for pipe operation
library(purrr)
#> Warning: le package 'purrr' a été compilé avec la version R 3.5.2
ex_list <- list('a' = list(1,2),'b'=list(list(3,4), list(5,6)), 'c' = 'hello')
# use magrittr function
ex_list %>%
magrittr::extract(c("a", "c"))
#> $a
#> $a[[1]]
#> [1] 1
#>
#> $a[[2]]
#> [1] 2
#>
#>
#> $c
#> [1] "hello"
Created on 2019-02-26 by the reprex package (v0.2.1)
4 Likes
thanks but what is the advantage of extract
when I can use .[]
as above? its even shorter
cderv
February 27, 2019, 6:30am
7
1 Like
system
Closed
March 6, 2019, 6:31am
8
This topic was automatically closed 7 days after the last reply. New replies are no longer allowed. If you have a query related to it or one of the replies, start a new topic and refer back with a link.