208 votes

Accéder aux noms d'index lapply dans FUN

Est-il possible d'obtenir la liste nom de l'index dans mon lapply() la fonction?

n = names(mylist)
lapply(mylist, function(list.elem) { cat("What is the name of this list element?\n" })

J'ai demandé avant si c'est possible afin de préserver l'index des noms dans le lapply() a retourné la liste, mais je ne sais toujours pas si il existe un moyen facile de récupérer chaque nom d'élément à l'intérieur de la fonction personnalisée. Je voudrais éviter d'appeler lapply sur les noms eux-mêmes, je préfère obtenir le nom dans les paramètres de la fonction.

201voto

Tommy Points 16323

Malheureusement, lapply ne vous donne que les éléments du vecteur de passer. Le travail habituel de contournement consiste à transmettre les noms ou les indices du vecteur au lieu du vecteur lui-même.

Mais notez que vous pouvez toujours passer en arguments supplémentaires à la fonction, de sorte que les œuvres suivantes:

x <- list(a=11,b=12,c=13) # Changed to list to address concerns in commments
lapply(seq_along(x), function(y, n, i) { paste(n[[i]], y[[i]]) }, y=x, n=names(x))

Ici, j'utilise lapply sur les indices de l' x, mais aussi transmettre en x et les noms de x. Comme vous pouvez le voir, l'ordre des arguments de la fonction peut être n'importe quoi - lapply passera à la "élément" (ici l'index) pour le premier argument non spécifié parmi les plus. Dans ce cas, je spécifier y et n, donc il n'y a qu' i gauche...

Qui produit le texte suivant:

[[1]]
[1] "a 11"

[[2]]
[1] "b 12"

[[3]]
[1] "c 13"

Mise à JOUR de plus Simple exemple, le même résultat:

lapply(seq_along(x), function(i) paste(names(x)[[i]], x[[i]]))

Ici, la fonction utilise le "global" de la variable x et extrait les noms de chaque appel.

61voto

caracal Points 966

Cela utilise essentiellement la même solution que Tommy, mais avec Map() , il n’est pas nécessaire d’accéder aux variables globales qui stockent les noms des composants de liste.

 > x <- list(a=11, b=12, c=13)
> Map(function(x, i) paste(i, x), x, names(x))
$a
[1] "a 11"

$b
[1] "b 12"

$c
[1] "c 13
 

Ou, si vous préférez mapply()

 > mapply(function(x, i) paste(i, x), x, names(x))
     a      b      c 
"a 11" "b 12" "c 13"
 

44voto

Ferdinand.kraft Points 7013

Oui, vous pouvez l'obtenir en utilisant ceci:

> lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])

Résultat:

$a
[1] 1

$b
[1] 2

$c
[1] 3

Explication: lapply crée des appels de la forme FUN(X[[1L]], ...), FUN(X[[2L]], ...) etc. Donc, l'argument qu'il passe est - X[[i]]i est l'index courant dans la boucle. Si nous obtenons ce avant c'est évaluée (c'est à dire, si nous utilisons substitute), nous obtenons le non évaluée expression X[[i]]. C'est un appel à l' [[ de la fonction, avec des arguments X (un symbole) et i (un entier). Donc, substitute(x)[[3]] renvoie précisément cet entier.

Ayant l'index, vous pouvez accéder aux noms trivialement, si vous tout d'abord l'enregistrer comme ceci:

L <- list(a=10,b=10,c=10)
n <- names(L)
lapply(L, function(x)n[substitute(x)[[3]]])

Résultat:

$a
[1] "a"

$b
[1] "b"

$c
[1] "c"

Ou à l'aide de cette deuxième astuce: :-)

lapply(list(a=10,b=10,c=10), function(x)names(eval(sys.call(1)[[2]]))[substitute(x)[[3]]])

(le résultat est le même).

Explication 2: sys.call(1) retours lapply(...), de sorte qu' sys.call(1)[[2]] est l'expression utilisée comme liste d'argument lapply. En la passant à l' eval crée un légitime objet names peut accéder. Délicat, mais il fonctionne.

Bonus: une deuxième façon d'obtenir les noms de:

lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])

Notez que X est un objet valide dans le cadre parent d' FUN, et les références de la liste argument de l' lapply, de sorte que nous pouvons obtenir avec eval.parent.

5voto

BondedDust Points 105234

La réponse de Tommy s’applique aux vecteurs nommés, mais j’ai eu l’idée que les listes vous intéressaient. Et il semble qu'il se soit arrêté parce qu'il faisait référence à "x" dans l'environnement d'appel. Cette fonction utilise uniquement les paramètres qui ont été transmis à la fonction et n'émet donc aucune hypothèse sur le nom des objets transmis:

 x <- list(a=11,b=12,c=13)
lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } )
#--------
$a
NULL

$b
NULL

$c
NULL
#--------
 names( lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } ))
#[1] "a" "b" "c"
 what_is_my_name <- function(ZZZ) return(deparse(substitute(ZZZ)))
 what_is_my_name(X)
#[1] "X"
what_is_my_name(ZZZ=this)
#[1] "this"
 exists("this")
#[1] FALSE
 

4voto

Julian Points 1

Ma réponse va dans le même sens que Tommy et caracals, mais évite d'avoir à enregistrer la liste comme un objet supplémentaire.

lapply(seq(3), function(i, y=list(a=14,b=15,c=16)) { paste(names(y)[[i]], y[[i]]) })

Résultat:

[[1]]
[1] "a 14"

[[2]]
[1] "b 15"

[[3]]
[1] "c 16"

Cela donne la liste comme un argument nommé pour le PLAISIR (au lieu de lapply). lapply n'a qu'à parcourir les éléments de la liste (attention au changement de ce premier argument de lapply lors de la modification de la longueur de la liste).

Remarque: la remise de la liste directement à lapply comme un argument supplémentaire fonctionne aussi:

lapply(seq(3), function(i, y) { paste(names(y)[[i]], y[[i]]) }, y=list(a=14,b=15,c=16))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X