window.addEventListener('load', function(){
console.log('window loaded');
});
我想总结一下" a"根据" b"形成一个新的清单。
即(5 + 6 + 8),(4 + 5),2
预期结果是:
a<-list(5,6,8,4,5,2)
b<-c(3,2,1)
我使用下面的代码来解决这个问题,但我想知道是否有更方便的方法来解决这个问题。谢谢!
[[1]]
[1] 19
[[2]]
[1] 9
[[3]]
[1] 2
答案 0 :(得分:8)
我已经想到了这个问题的有趣解决方案,这可能有点奇怪,但我喜欢它:
as.list(diff(c(0,cumsum(a)[cumsum(b)])));
## [[1]]
## [1] 19
##
## [[2]]
## [1] 9
##
## [[3]]
## [1] 2
##
首先,我们使用cumsum()
获取完整的累积总和。注意:我最初认为cumsum()
需要原子矢量(例如sum()
),因此我最初在unlist()
之前调用了cumsum()
,但感谢@thelatemail指出它也可以与列表一起使用!
cumsum(a);
## [1] 5 11 19 23 28 30
然后通过在cumsum(b)
上建立索引来提取要求和的范围的端点:
cumsum(b);
## [1] 3 5 6
cumsum(a)[cumsum(b)];
## [1] 19 28 30
我们可以通过diff()
使用前导零来生成所需的求和:
diff(c(0,cumsum(a)[cumsum(b)]));
## [1] 19 9 2
由于您希望将结果作为列表,我们最终需要调用as.list()
:
as.list(diff(c(0,cumsum(a)[cumsum(b)])));
## [[1]]
## [1] 19
##
## [[2]]
## [1] 9
##
## [[3]]
## [1] 2
##
lightsnail <- function() { p<-rep(1:length(b),b); as.list(sapply(1:length(b), function(x) {sum(as.numeric(a)[which(p==x)])})); };
thelatemail <- function() as.list(tapply(unlist(a), rep(seq_along(b), b), sum)); ## added as.list()
psidom <- function() lapply(split(unlist(a), rep(seq_along(b), b)), sum);
tfc <- function() as.list(aggregate(unlist(a), list(rep(1:length(b),b)), sum)[["x"]]);
user20650 <- function() as.list(rowsum(unlist(a), rep(seq_along(b), b), reorder=FALSE));
bgoldst <- function() as.list(diff(c(0,cumsum(a)[cumsum(b)])));
expected <- list(19,9,2);
identical(expected,lightsnail());
## [1] TRUE
identical(expected,unname(thelatemail())); ## ignore names
## [1] TRUE
identical(expected,unname(psidom())); ## ignore names
## [1] TRUE
identical(expected,tfc());
## [1] TRUE
identical(expected,user20650());
## [1] TRUE
identical(expected,bgoldst());
## [1] TRUE
library(microbenchmark);
microbenchmark(lightsnail(),thelatemail(),psidom(),tfc(),user20650(),bgoldst(),times=1e3L);
## Unit: microseconds
## expr min lq mean median uq max neval
## lightsnail() 26.088 33.358 37.34079 37.206 39.344 100.927 1000
## thelatemail() 121.881 135.139 151.77782 142.837 150.963 3547.386 1000
## psidom() 48.753 55.595 61.13800 59.016 63.507 276.693 1000
## tfc() 574.767 613.256 646.64302 628.652 645.757 1923.586 1000
## user20650() 17.534 23.094 25.49522 25.232 26.943 101.782 1000
## bgoldst() 10.264 14.969 17.61914 17.535 18.817 82.965 1000
答案 1 :(得分:3)
另一种选择:lapply(split(unlist(a), rep(seq_along(b), b)), sum)
答案 2 :(得分:2)
首先,当您实际使用向量时,没有理由使用列表。然后另外两种方法如下:
a <- c(5, 6, 8, 4, 5, 2)
b <- c(3, 2, 1)
f <- function(a, b) c(sum(head(a, b[1])), if(length(b) > 1) f(tail(a, -b[1]), b[-1]))
f(a, b)
# [1] 19 9 2
library(Matrix)
(a %*% bdiag(lapply(b, rep, x = 1)))[1, ]
# [1] 19 9 2
第一个是递归的,它在每个调用中不断缩短a
和b
,而第二个方法构造一个辅助块对角矩阵。
答案 3 :(得分:0)
不确定它是否更方便,但您可以将聚合与您创建的索引一起使用(p):
as.list(aggregate(unlist(a), list(rep(1:length(b),b)), sum)[["x"]])