#r #list #loops
#r #Список #циклы
Вопрос:
У меня много переменных в R, все типа list
a100 = list()
a200 = list()
# ...
p700 = list()
Каждая переменная представляет собой сложную структуру данных:
a200$time$data # returns 1000 x 1000 matrix
Теперь я хочу применить код к каждой переменной по очереди. Однако, поскольку R не поддерживает передачу по ссылке, я не уверен, что делать.
Одна из моих идей заключалась в том, чтобы создать большой список из всех этих списков, т.е.,
biglist = list()
biglist[[1]] = a100
...
И тогда я мог бы перебрать biglist:
for (i in 1:length(biglist)){
biglist[[i]]$newstuff = "profit"
# more code here
}
И, наконец, после цикла вернитесь назад, чтобы существующий код (использующий имена переменных) все еще работал:
a100 = biglist[[1]]
# ...
Вопрос в том, есть ли лучший способ перебора набора именованных списков? У меня такое чувство, что я делаю что-то ужасно неправильно. Есть ли что-нибудь попроще, например:
# FAKE, Idealized code:
foreach x in (a100, a200, ....){
x$newstuff = "profit"
}
a100$newstuff # "profit"
Ответ №1:
Для параллельного обхода списков вы можете использовать mapply, который будет принимать параллельные списки, а затем проходить по ним с шагом блокировки. Кроме того, на функциональном языке вы должны создавать нужный объект, а не изменять структуру данных в вызове функции.
Вам следует использовать семейство функций sapply, apply, lapply, ….
джим
Комментарии:
1. Спасибо за мысли, Джим. Как я могу использовать lapply и при этом изменять исходные списки? Например, если бы я это сделал
lapply(biglist, function(x){x$newstuff = "profit"; x})
, оригиналbiglist
не был бы изменен, не так ли? Каждыйx
будет просто выводиться на экран, нигде не сохраняясь?2. Джим — Поразмыслив об этом еще немного, я решил, что ваш совет выдавать объект, а не изменять его, является верным. Гораздо лучше структурировать мой код как
a100 = computeStuff(a100)
, чем все те сложности, о которых я думал. Спасибо за этот совет.
Ответ №2:
джимми совершенно прав. lapply
и sapply
специально разработаны для работы со списками. Таким образом, они будут работать и с вашим biglist. Однако вы не должны забывать возвращать объект во вложенной функции: пример :
X <- list(A=list(A1=1:2,A2=3:4),B=list(B1=5:6,B2=7:8))
lapply(X,function(i){
i$newstuff = "profit"
return(i)
})
Теперь, как вы сказали, R передается по значению, поэтому у вас есть несколько копий данных, перемещающихся по всему. Если вы работаете с действительно большими списками, возможно, вам захочется попробовать снизить потребление памяти, работая с каждой переменной отдельно, используя assign
и get
. Следующее считается неправильным кодированием, но иногда может быть необходимо, чтобы избежать проблем с памятью :
A <- X[[1]] ; B <- X[[2]] #make the data
list.names <- c("A","B")
for (i in list.names){
tmp <- get(i)
tmp$newstuff <- "profit"
assign(i,tmp)
rm(tmp)
}
Убедитесь, что вы хорошо осведомлены о значении этого кода, поскольку вы работаете в глобальной среде. Если вам нужно делать это чаще, возможно, вы захотите вместо этого работать со средами :
my.env <- new.env() # make the environment
my.env$A <- X[[1]];my.env$B <- X[[2]] # put vars in environment
for (i in list.names){
tmp <- get(i,envir=my.env)
tmp$newstuff <- "profit"
assign(i,tmp,envir=my.env)
rm(tmp)
}
my.env$A
my.env$B