将列表的元素附加到该列表的下一个元素

appending elements of list to the next element of that list

假设我正在处理一个列表列表,如下所示:

lol <- list(l1 = list(a = c(1:3), b = c(4:6), c = 2),
            l2 = list(a = c(1:3), b = c(4:6)),
            l3 = list(a = c(1:3), b = c(4:6)))

我想应用一个函数,比如:

foo <- function(x){
  sum(x$a, x$b)*x$c
}

第一个列表中的元素 c 需要附加到列表中的下一个元素 (l2) 才能使函数正常工作。所以算法是:

A) 计算 sum(a, b) 乘以 c -> 结果为 newc.

B) 将 newc 附加到下一个列表,称其为 c

C) 重复

我知道如何循环执行,如下:

for(i in 1:length(lol)){
    s <- lol[[i]]
    s[["newc"]] <- foo(s)
    lol[[i]] <- list()
    lol[[i]] <- s
    if((i+1)<(length(lol)+1)){
      lol[[i+1]][["c"]] <- lol[[i]][["newc"]]
    }
} 

就我而言,我必须使用更多数据(列表中的更多列表)执行此操作并迭代很多次(最少 100 次),这给了我很高的运行时间(在某些试验中大约 2 秒)。由于我需要将其用于越来越多的海量数据,因此我希望有替代此循环的方法。

编辑:感谢您的回答。不过我需要澄清一下,我的列表中同时需要 c 和 newc。之前不清楚。谢谢。

你有没有关于如何在没有循环的情况下解决这个问题的想法? 谢谢!

我不会使用循环:

lol <- lapply(lol, \(x) c(x, c=lol[[1]]$c))
lapply(lol, foo)

问题可以改写为根据列表的前一个元素更新列表的当前元素。
循环可以简化为 one-liner:

lol <- list(l1 = list(a = c(1:3), b = c(4:6), c = 2),
            l2 = list(a = c(1:3), b = c(4:6)),
            l3 = list(a = c(1:3), b = c(4:6)))

foo <- function(x){
  sum(x$a, x$b)*x$c
}

for(i in seq_along(lol)[-1]){
  lol[[i]][["c"]] <- foo(lol[[i - 1L]])
} 

lol
#> $l1
#> $l1$a
#> [1] 1 2 3
#> 
#> $l1$b
#> [1] 4 5 6
#> 
#> $l1$c
#> [1] 2
#> 
#> 
#> $l2
#> $l2$a
#> [1] 1 2 3
#> 
#> $l2$b
#> [1] 4 5 6
#> 
#> $l2$c
#> [1] 42
#> 
#> 
#> $l3
#> $l3$a
#> [1] 1 2 3
#> 
#> $l3$b
#> [1] 4 5 6
#> 
#> $l3$c
#> [1] 882

reprex package (v2.0.1)

于 2022-05-11 创建

编辑

这是另一个解决方案,基于

lol <- list(l1 = list(a = c(1:3), b = c(4:6), c = 2),
            l2 = list(a = c(1:3), b = c(4:6)),
            l3 = list(a = c(1:3), b = c(4:6)))

foo <- function(x, y) {
  sum(y$a, y$b)*x
}

newc <- Reduce(foo, lol[-1], init = lol[[1]][["c"]], accumulate = TRUE)
Map(\(x, newc) {x[["c"]] <- newc; x}, lol, newc)
#> $l1
#> $l1$a
#> [1] 1 2 3
#> 
#> $l1$b
#> [1] 4 5 6
#> 
#> $l1$c
#> [1] 2
#> 
#> 
#> $l2
#> $l2$a
#> [1] 1 2 3
#> 
#> $l2$b
#> [1] 4 5 6
#> 
#> $l2$c
#> [1] 42
#> 
#> 
#> $l3
#> $l3$a
#> [1] 1 2 3
#> 
#> $l3$b
#> [1] 4 5 6
#> 
#> $l3$c
#> [1] 882

reprex package (v2.0.1)

于 2022-05-11 创建

编辑 2

要在结果中也有 newc,可以执行以下任一操作。
注意 与上述解决方案一样,解决方案具有 不同 功能 foo。第二个是 Ritchie Sacramento 评论中的函数,现已删除,我已在上面的 Reduce/Map 解决方案中重现。

解决方案 1,newc

foo <- function(x){
  sum(x$a, x$b)*x$c
}

for(i in seq_along(lol)[-1L]){
  lol[[i]][["c"]] <- foo(lol[[i - 1L]])
  lol[[i]][["newc"]] <- foo(lol[[i]])
} 

lol

解决方案 2,newc

foo <- function(x, y) {
  sum(y$a, y$b)*x
}

newc <- Reduce(foo, lol, init = lol[[1]][["c"]], accumulate = TRUE)
Map(\(x, c, newc) {
  x[["c"]] <- c
  x[["newc"]] <- newc
  x
}, lol, newc[-length(newc)], newc[-1])

lol