为了用完全可重复的数据集说明手头的问题,我有以下简化的对象:
set.seed(7)
animalL <- list(mittens=list(what='cat', paws=4), lassie=list(what='dog', paws=4))
timeL <- list(list(foo=rnorm(2)), list(foo=rnorm(2)), list(foo=rnorm(2)))
houseL <- list(houseA=list(zip=123, roomL=list(den='some:blueprint', den2='another:blueprint')), houseB=list(zip=456, roomL=list(cove='a:blueprint', cove2='oneMore:blueprint')))
所以有一个动物列表,每个动物都有自己的特征和相关数据。有一个“时间段”列表,每个时间段都有与它们相关的各种功能(这里简化为大小为2的数字向量)。最后,有一个房屋清单,每个房屋都有一系列可能不同长度的房间。根据这些数据,我能够在每个房子的所有时间段的总和上评估每个动物“体验”的样子。然而,在每个房子的每个房间里,让每只动物在每个时间段内闲逛后,我才能这样做。对于后者,我有这个功能:
evaluateHangOutInRoom <- function(animal, timePeriod, house, room) {
list(x=rnorm(1), y=rnorm(1))
}
在现实生活中,这个功能非常慢,所以我需要并行运行它。我有一个内部库,但它的界面只是lapply
的界面。假设是这样的:
fastLapply <- function(X, FUN) {
#in reality this is massively distributed
lapply(X, FUN)
}
我可以尝试通过索引数学来做到这一点,如下所示:
AA <- length(animalL)
TT <- length(timeL)
RR <- cumprod(lapply(houseL, function(house) length(house$roomL)))
fastLapply(1:(AA*TT*RR), function(idx) 0)
但它很容易从idx
退出到环聊功能的参数。
我可以尝试构建我需要处理的每个“场景”的数组:
hangOutArgArray <- array('', dim=c(AA, TT, RR))
dimnames(hangOutArgArray)[[1]] <- as.list(animalL)
dimnames(hangOutArgArray)[[3]] <- as.list(names(unlist(lapply(houseL, function(house) lapply(house$roomL, function(room) NULL)), recursive=FALSE)))
在数组dimnames上可能有类似Map
的东西,而数组本身可以生成一个平面列表,我可以很容易地重新组织回到数组形状之后 - 但这很讨厌......
如何平滑这些不同的情况以传递到fastLapply,这样我就可以采用相同长度的扁平输出并轻松地将其重新构造成易于使用的多维布局以供后续处理?目前这是上述令人讨厌(但有效)的方法:
argumentArray <- array('', dim=c(AA, TT, RR))
dimOneNames <- as.list(names(animalL))
dimThreeNames <- as.list(names(unlist(lapply(houseL, function(house) lapply(house$roomL, function(room) NULL)), recursive=FALSE)))
dimnames(argumentArray)[[1]] <- dimOneNames
dimnames(argumentArray)[[3]] <- dimThreeNames
invisible(lapply(dimOneNames, function(d1) lapply(1:TT, function(d2), lapply(dimThreeNames, function(d3) { argumentArray[d1, d2, d3] <<- paste(d1, d2, d3, sep=';')}))))
resultL <- fastLapply(argumentArray, function(argStr) {
argV <- unlist(strsplit(argStr, ';', fixed=TRUE))
animal <- argV[1]
timePrd <- timeL[[ as.integer(argV[2]) ]]
house <- houseL[[ unlist(strsplit(argV[3], '.', fixed=TRUE))[1] ]]
room <- house$roomL[[ unlist(strsplit(argV[3], '.', fixed=TRUE))[2] ]]
evaluateHangOutInRoom(animal, timePrd, house, room)
})
resultArray <- array(resultL, dim=dim(argumentArray))
dimnames(resultArray) <- dimnames(argumentArray)