web-dev-qa-db-fra.com

Utilisez l'entrée de la fonction de carte de purrr pour créer une liste nommée comme sortie dans R

J'utilise la fonction map du paquet purrr dans R qui donne en sortie une liste. Maintenant, je voudrais que la sortie soit une liste nommée basée sur l'entrée. Un exemple est donné ci-dessous.

input <- c("a", "b", "c")
output <- purrr::map(input, function(x) {paste0("test-", x)})

À partir de cela, je voudrais accéder aux éléments de la liste en utilisant:

output$a

Ou

output$b
19
Michael

Nous avons juste besoin de nommer le list

names(output) <- input

puis extraire les éléments en fonction du nom

output$a
#[1] "test-a"

Si cela doit être fait en utilisant tidyverse

library(tidyverse)
output <- map(input, ~paste0('test-', .)) %>% 
                                setNames(input)
22
akrun

La solution acceptée fonctionne, mais souffre d'un argument répété (input) qui peut provoquer des erreurs et interrompre le flux lors de l'utilisation de la tuyauterie avec %>%.

Une solution alternative consisterait à utiliser un peu plus de puissance du %>% opérateur

1:5 %>% { set_names(map(., ~ .x + 3), .) } %>% print # ... or something else

Cela prend l'argument de la pipe mais manque encore de beauté. Une alternative pourrait être une petite méthode d'aide telle que

map_named = function(x, ...) map(x, ...) %>% set_names(x)

1:5 %>% map_named(~ .x + 1)

Cela semble déjà plus joli et élégant. Et ce serait ma solution préférée.

Enfin, nous pourrions même écraser purrr::map dans le cas où l'argument est un vecteur caractère ou entier et produit une liste nommée dans un tel cas.

map = function(x, ...){
    if (is.integer(x) | is.character(x)) {
        purrr::map(x, ...) %>% set_names(x)
    }else {
        purrr::map(x, ...) 
    }
}

1 : 5 %>% map(~ .x + 1)

Cependant, la solution optimale serait que purrr implémente un tel comportement hors de la boîte.

5
Holger Brandl