web-dev-qa-db-fra.com

Accéder aux noms de liste et les conserver dans la fonction lapply

Je dois accéder aux noms de liste dans la fonction lapply. J'ai trouvé des discussions en ligne où il est dit que je devrais parcourir les noms de la liste pour pouvoir récupérer chaque nom d'élément de liste dans ma fonction:

> n = names(mylist)
> mynewlist = lapply(n, function(nameindex, mylist) { return(mylist[[nameindex]]) }, mylist)
> names(mynewlist)
NULL
> names(mynewlist) = n

Le problème est que mynewlist perd les index mylist d'origine et je dois ajouter cette affectation last names () pour les restaurer.

Est-il possible de donner un nom d'index explicite à chaque élément renvoyé par la fonction lapply? Ou une autre façon de vous assurer que les éléments de la nouvelle liste ont les noms d'index corrects? Je pense que les noms d’index de ma nouvelle liste pourraient être erronés si lapply ne renvoie pas les éléments de la liste dans le même ordre que mylist.

40
Robert Kubrick

Je crois que lapply par défaut conserve l'attribut de noms de ce que vous parcourez. Lorsque vous stockez les noms de myList dans n, ce vecteur ne comporte plus de "noms". Donc, si vous rajoutez cela via,

names(n) <- names(myList)

et utilisez lapply comme précédemment, vous devriez obtenir le résultat souhaité.

Modifier

Mon cerveau un peu brumeux ce matin. Voici une autre option, peut-être plus pratique:

sapply(n,FUN = ...,simplify = FALSE,USE.NAMES = TRUE)

J'étais à tâtons, confus que lapply n'avait pas d'argument USE.NAMES, puis j'ai regardé le code pour sapply et me suis rendu compte que j'étais ridicule et que c'était probablement une meilleure façon de faire.

42
joran

la fonction setNames est un raccourci utile ici

mylist <- list(a = TRUE, foo = LETTERS[1:3], baz = 1:5)
n <- names(mylist)
mynewlist <- lapply(setNames(n, n), function(nameindex) {mylist[[nameindex]]})

qui conserve les noms

> mynewlist
$a
[1] TRUE

$foo
[1] "A" "B" "C"

$baz
[1] 1 2 3 4 5
35
Brian Diggs

Avez-vous examiné llply() dans le package plyr?

Il fait exactement ce que vous demandez. Pour chaque élément d'une liste, appliquez une fonction en conservant les résultats sous forme de liste. llply est équivalent à lapply, sauf qu'il conservera les étiquettes et peut afficher une barre de progression. de ?llply

mylist <- list(foo1=1:10,foo2=11:20)
>names(mylist)
[1] "foo1" "foo2"
newlist<- llply(mylist, function(x) mean(x))

>names(newlist)
[1] "foo1" "foo2"
7
Maiasaura

S'appuyant sur la réponse de Joran et la précisant:

Le wrapper sapply(USE.NAMES=T) définira en effet comme noms du résultat final les valeurs du vecteur sur lequel vous effectuez une itération (et non son attribut names comme lapply), mais uniquement s'il s'agit de caractères.

En conséquence, les indices de passage ne vont pas aider. Si vous voulez passer des index avec sapply, vous devez recourir à un casting (laid):

sapply(as.character(c(1,11)), function(i) TEST[[as.numeric(i)]], USE.NAMES = TRUE)

Dans ce cas, une solution plus propre consiste à définir et à utiliser directement les noms de votre objet d'origine. Voici une liste exhaustive de solutions:

TEST <- as.list(LETTERS[1:12])

### lapply ##
## Not working because no name attribute
lapply(c(1,11), function(i) TEST[[i]])

## working but cumbersome
index <- c(1,11)
names(index) <- index
lapply(index, function(i) TEST[[i]])

### sapply ##
## Not working because vector elements are not strings
sapply(c(1,11), function(i) TEST[[i]], simplify = F) 

## Working with the casting trick
sapply(as.character(c(1,11)), function(i) TEST[[as.numeric(i)]], simplify = F)

## Cleaner, using names with sapply:
names(TEST) <- LETTERS[26:15] 
sapply(names(TEST)[c(1,11)], function(name) TEST[[name]], simplify = F) 
5
Antoine Lizée

imap() du paquet purrr convient à votre problème.

library(purrr)
mylist <- list(foo1=1:10,foo2=11:20)
imap(mylist, function(x, y) mean(x)) ## x is the value, y is the name

ou vous pouvez utiliser une version plus compacte de imap:

imap(mylist, ~ mean(.x))

Notez que vous pouvez utiliser des variantes de imap_xxx en fonction du type de vecteur souhaité:

imap_dbl(mylist, ~ mean(.x)) ## will return a named numeric vector. 
1
Kevin Zarca