Dostęp i zachowanie nazw list w funkcji lapply

Muszę uzyskać dostęp do nazw list wewnątrz funkcji lapply. Znalazłem kilka wątków w Internecie, gdzie mówi się, że powinienem iterację przez nazwy listy, aby móc pobrać nazwę każdego elementu listy w mojej funkcji:

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

Problem polega na tym, że mynewlist traci oryginalne indeksy mylist i muszę dodać przypisanie last names (), aby je przywrócić.

Czy istnieje sposób na podanie jawnej nazwy indeksu dla każdego elementu zwracanego przez funkcję lapply? Lub inny sposób na zrobienie czy elementy mynewlist mają ustawione poprawne nazwy indeksów? Uważam, że nazwy indeksów myynewlist mogą się mylić, jeśli lapply nie zwróci elementów listy w tej samej kolejności, co mylist.

Author: Robert Kubrick, 2012-02-27

5 answers

Wierzę, że lapply domyślnie zachowuje atrybut nazw tego, co iterujesz. Po zapisaniu nazw myList w n, wektor ten nie ma już żadnych "nazw". Więc jeśli dodasz to z powrotem w via,

names(n) <- names(myList)

I użycie {[2] } Jak wcześniej, należy uzyskać pożądany efekt.

Edit

Mój mózg trochę zamglony dziś rano. Oto inna, być może wygodniejsza opcja:
sapply(n,FUN = ...,simplify = FALSE,USE.NAMES = TRUE)

Po omacku, zdezorientowany, że lapply nie miał USE.NAMES kłótnia, a potem właściwie spojrzałem na kod {[8] } i zdałem sobie sprawę, że byłem głupi, i to był prawdopodobnie lepszy sposób.

 39
Author: joran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-27 18:51:02

Funkcja setNames jest użytecznym skrótem

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

Który zachowuje nazwy

> mynewlist
$a
[1] TRUE

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

$baz
[1] 1 2 3 4 5
 33
Author: Brian Diggs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-30 17:05:20

Czy przyjrzałeś się llply() z paczki plyr?

Robi dokładnie to, o co prosisz. dla każdego elementu listy, zastosuj funkcję, zachowując wyniki jako listę. llply jest odpowiednikiem lapply z tym wyjątkiem, że zachowa etykiety i może wyświetlać pasek postępu. z ?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"
 6
Author: Maiasaura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-28 01:06:38

[[4]] bazując na odpowiedzi jorana i precyzując ją:

Wrapper sapply(USE.NAMES=T) rzeczywiście ustawi jako nazwy wyniku końcowego wartości wektora, nad którym się iterujesz (a nie jego atrybutu names, jak lapply), ale tylko wtedy, gdy są to znaki.

W rezultacie przechodzenie indeksów nie pomoże. Jeśli chcesz przekazać indeksy z sapply, musisz uciekać się do jakiegoś (brzydkiego) castingu:

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

W tym przypadku czystszym rozwiązaniem jest bezpośrednie ustawienie i użycie nazw twojego oryginalny obiekt. Oto wyczerpująca lista rozwiązań:

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
Author: Antoine Lizée,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-29 11:27:28

imap() z pakietu purrr jest miły dla Twojego problemu.

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

Lub możesz użyć bardziej kompaktowej wersji imap:

imap(mylist, ~ mean(.x))

Zauważ, że możesz użyć wariacji imap_xxx w zależności od typu wektora, który chcesz:

imap_dbl(mylist, ~ mean(.x)) ## will return a named numeric vector. 
 1
Author: Kevin Zarca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-07 20:08:24