2012-02-27 11 views
34

Potrzebuję dostępu do nazw list wewnątrz funkcji lapply. Znalazłem kilka wątków w Internecie, gdzie jest powiedziane mam iterację nazwisk na liście, aby móc sprowadzić każdej listy nazwę elementu w mojej funkcji:Dostęp i zachowanie nazw list w funkcji lapply

> 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 podania jawnej nazwy indeksu dla każdego elementu zwróconego przez funkcję lapply? Lub inny sposób, aby upewnić się, że elementy mynewlist mają ustawione prawidłowe nazwy indeksów? Czuję, że moje indeksy nazw indeksów mogą być błędne, jeśli lapply nie zwraca elementów listy w tej samej kolejności niż moja lista.

Odpowiedz

33

Wierzę, że domyślnie lapply zachowuje atrybut names tego, co robisz iterująco. Gdy przechowujesz nazwy myList w n, ten wektor nie ma już żadnych "nazw". Więc jeśli dodać że już w Via,

names(n) <- names(myList) 

i wykorzystanie lapply jak poprzednio, należy uzyskać pożądany rezultat.

Edytuj

Mój mózg nieco mglisty rano. Oto kolejny, być może bardziej wygodne, opcja:

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

byłem po omacku ​​o zmieszany że lapply nie miał USE.NAMES argumentu, a potem rzeczywiście wyglądał na kod dla sapply i uświadomiłem sobie, że są głupie, a prawdopodobnie był to lepszy sposób.

+0

Tak, to działa. Nadal muszę utworzyć "n" chociaż przez n = names (myList). Dwa wywołania do nazw (myList), jeden raz do utworzenia n, drugi do ustawienia n atrybutów. –

+1

Możesz zastąpić drugi z 'names (n) <- n' though. – Aaron

+0

@RobertKubrick Zobacz moją edycję dla możliwie ładniejszego rozwiązania. Sprawdź kod 'sapply', aby zobaczyć, jak bardzo jest to proste; działa tylko jako opakowanie, które dodaje imiona po fakcie. – joran

5

Czy przejrzałeś llply() z paczki plyr?

Wykonuje dokładnie to, o co prosisz. Dla każdego elementu listy zastosuj funkcję, zachowując wyniki jako listę. llply jest odpowiednikiem lapply, z tą różnicą, że zachowa etykiety i wyświetli 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" 
+0

Hmm. To wygląda dokładnie na to, co "lapply" robi. Zobacz na przykład 'lapply (mylist, mean)' i 'llply (names (mylist), function (x) mean (mylist [[x]]))'. Wszelkie pomysły, co oznacza "zachować etykiety"? – Aaron

+0

Myślę, że 'mlply' zrobiłby to – baptiste

4

Opierając się na odpowiedź Jøran, a doprecyzowanie go:

sapply(USE.NAMES=T) wrapper rzeczywiście ustawiony jako nazw wyniku końcowego wartości wektora jesteś iteracji nad (i nie przypisują jej nazwy jak lapply), , ale tylko jeśli są to znaki.

W rezultacie przekazywanie indeksów nie pomoże. Jeśli chcesz przekazać indeksy z sapply, trzeba uciekać się do pewnego (brzydki) odlewu:

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

W tym przypadku rozwiązaniem jest czystsze bezpośrednio ustawić i używać nazwy oryginalnego obiektu.Tutaj jest to 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) 
32

funkcja setNames jest użyteczny skrót tutaj

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 nazw

> mynewlist 
$a 
[1] TRUE 

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

$baz 
[1] 1 2 3 4 5 
1

imap() z pakietu purrr jest miła dla twojego problem.

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 użyć bardziej kompaktową wersję IMAP:

imap(mylist, ~ mean(.x)) 

pamiętać, że można użyć odmiany imap_xxx zależności od rodzaju wektorem chcesz:

imap_dbl(mylist, ~ mean(.x)) ## will return a named numeric vector. 
Powiązane problemy