2012-02-27 7 views
34

Necesito acceder a los nombres de lista dentro de la función de aplicar. He encontrado algunos hilos en línea donde se dice que debería repetir por los nombres de la lista para ser capaz de ir a buscar cada una lista de nombres de elemento en mi función:Acceda y conserve los nombres de la lista en la función de aplicar

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

El problema es que mynewlist pierde los índices MyLIST originales y Tengo que agregar esa asignación de apellidos() para restaurarlos.

¿Hay alguna manera de dar un nombre de índice explícito a cada elemento devuelto por la función lapply? ¿O una forma diferente de asegurarse de que los elementos de mynewlist tengan los nombres de índice correctos? Siento que los nombres de los índices de mi lista podrían estar equivocados si la aplicación no devuelve los elementos de la lista en el mismo orden que mylist.

Respuesta

33

Creo que lapply de forma predeterminada mantiene el atributo de los nombres de lo que esté iterando. Cuando almacena los nombres de myList en n, ese vector ya no tiene ningún "nombre". Así que si se agrega que, ya en vía,

names(n) <- names(myList) 

y el uso lapply como antes, usted debe obtener el resultado deseado.

Editar

sesos un poco de niebla de esta mañana. Aquí hay otro, quizás más conveniente, opción:

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

me tientas, confundido que lapply no tenían un argumento USE.NAMES, y luego en realidad se veía en el código para sapply y se dio cuenta que estaba siendo tonto, y esta fue probablemente una mejor forma de hacerlo.

+0

Sí, esto funciona. Todavía tengo que crear 'n' a través de n = names (myList). Dos llamadas a nombres (myList), una para crear n, la segunda para establecer n atributos. –

+1

Puede reemplazar el segundo con 'names (n) <- n' embargo. – Aaron

+0

@RobertKubrick Vea mi edición para una solución posiblemente más agradable. Examine el código de 'sapply' para ver qué tan simple es esto; simplemente actúa como un contenedor que agrega los nombres después del hecho. – joran

5

¿Has mirado en llply() desde el paquete plyr?

Hace exactamente lo que está pidiendo. Para cada elemento de una lista, aplique la función, manteniendo los resultados como una lista. llply es equivalente a aplicar, excepto que conservará las etiquetas y puede mostrar una barra de progreso. 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" 
+0

Hmm. Eso parece exactamente lo que 'lapply' hace. Ver por ejemplo 'lapply (mylist, mean)' y 'llply (names (mylist), function (x) mean (mylist [[x]]))'. ¿Alguna idea de lo que significa "conservar etiquetas"? – Aaron

+0

Creo que 'mlply' haría esto – baptiste

4

Sobre la base de la respuesta de Joran, y precisando que:

La envoltura sapply(USE.NAMES=T) será de hecho establecido como nombres del resultado final de los valores del vector que están interactuando sobre (y no atribuyen sus nombres like lapply), pero solo si se trata de caracteres.

Como resultado, los índices de aprobación no ayudarán. Si desea pasar índices con sapply, es necesario recurrir a alguna de fundición (feo):

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

En este caso, una solución más limpia es la creación y el uso de nombres de su objeto original directamente.Aquí es una lista exhaustiva de soluciones:

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) 
32

la función setNames es un atajo útil aquí

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

que conserva los nombres

> mynewlist 
$a 
[1] TRUE 

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

$baz 
[1] 1 2 3 4 5 
1

imap() del paquete purrr es agradable para su problema.

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 

o puede utilizar una versión más compacta del IMAP:

imap(mylist, ~ mean(.x)) 

Tenga en cuenta que puede utilizar variaciones de imap_xxx dependiendo del tipo de vector que desee:

imap_dbl(mylist, ~ mean(.x)) ## will return a named numeric vector. 
Cuestiones relacionadas