Подтвердить что ты не робот

Доступ и сохранение имен списков в функции lapply

Мне нужно получить доступ к именам списков внутри функции lapply. Я нашел некоторые потоки в Интернете, где он сказал, что я должен перебирать имена списка, чтобы иметь возможность отображать каждое имя элемента списка в моей функции:

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

Проблема в том, что mynewlist теряет исходные индексы mylist, и мне нужно добавить, что их имена() присваивают для их восстановления.

Есть ли способ дать явное имя индекса каждому элементу, возвращаемому функцией lapply? Или другой способ убедиться, что элементы mynewlist имеют правильные имена индексов? Я считаю, что имена имен mynewlist могут быть неправильными, если lapply не возвращает элементы списка в том же порядке, что и mylist.

4b9b3361

Ответ 1

Я считаю, что lapply по умолчанию сохраняет атрибут имен того, что вы итерируете. Когда вы сохраняете имена myList в n, этот вектор больше не имеет никаких "имен". Поэтому, если вы добавите это обратно через,

names(n) <- names(myList)

и использовать lapply, как и раньше, вы должны получить желаемый результат.

Edit

Сегодня утром мои мозги немного туманны. Вот еще один, возможно, более удобный вариант:

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

Я нащупывал, путал, что lapply не имеет аргумента USE.NAMES, а затем я действительно просмотрел код для sapply и понял, что я был глупым, и это, вероятно, лучший способ перейти.

Ответ 2

Функция setNames - полезный ярлык здесь

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

который сохраняет имена

> mynewlist
$a
[1] TRUE

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

$baz
[1] 1 2 3 4 5

Ответ 3

Вы просмотрели llply() из пакета plyr?

Он делает именно то, о чем вы просите. Для каждого элемента списка применяйте функцию, сохраняя результаты как список. llply эквивалентно lapply, за исключением того, что он сохранит метки и может отображать индикатор выполнения. от ?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"

Ответ 4

Основываясь на joran-ответе и уточняя его:

Оболочка sapply(USE.NAMES=T) действительно задает в качестве имен конечного результата значения вектора, который вы итерируете (а не его атрибут имен, например lapply), , но только если это символы.

В результате прохождение индексов не поможет. Если вы хотите передать индексы с помощью sapply, вам нужно прибегнуть к какому-то (уродливому) кастингу:

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

В этом случае более чистым решением является прямое задание и использование имен исходного объекта. Вот исчерпывающий список решений:

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

imap() из пакета purrr хорош для вашей проблемы.

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

или вы можете использовать более компактную версию imap:

imap(mylist, ~ mean(.x))

Обратите внимание, что вы можете использовать изменения imap_xxx в зависимости от типа нужного вам вектора:

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