折叠一种特殊的列表结构

Collapsing a special kind of list structure

提问人:Aku-Ville Lehtimäki 提问时间:10/10/2023 最后编辑:Uwe KeimAku-Ville Lehtimäki 更新时间:10/11/2023 访问量:79

问:

我在 R 中有一个以下类型的列表:

List of 4
 $ :List of 4
  ..$ prices  : num [1:5] -3.68 -1.5 1.71 1.75 -0.67
  ..$ lower   : num -2.92
  ..$ midpoint: num 1
  ..$ upper   : num 4.92
 $ :List of 4
  ..$ prices  : num [1:5] 0.15395 0.00512 0.02635 0.0388 0.17721
  ..$ lower   : num 0.00422
  ..$ midpoint: num 0.167
  ..$ upper   : num 0.615
 $ :List of 4
  ..$ prices  : num [1:5, 1:3] 0.841 0.514 1.443 1.096 0.913 ...
  ..$ lower   : num [1:3] -0.96 0.04 1.04
  ..$ midpoint: num [1:3] 1 2 3
  ..$ upper   : num [1:3] 2.96 3.96 4.96
 $ :List of 4
  ..$ prices  : num [1:5] 6.78 -0.28 2.565 0.553 14.275
  ..$ lower   : num -4.84
  ..$ midpoint: num 3
  ..$ upper   : num 10.8

上层列表中的第一项、第二项和第四项应按原样进行,但第三项应折叠为三个单独的项。因此,最终结果应如下所示:

List of 4
 $ :List of 4
  ..$ prices  : num [1:5] -3.68 -1.5 1.71 1.75 -0.67
  ..$ lower   : num -2.92
  ..$ midpoint: num 1
  ..$ upper   : num 4.92
 $ :List of 4
  ..$ prices  : num [1:5] 0.15395 0.00512 0.02635 0.0388 0.17721
  ..$ lower   : num 0.00422
  ..$ midpoint: num 0.167
  ..$ upper   : num 0.615
 $ :List of 4
  ..$ prices  : num [1:5] 1 2 3 ... #This should be the FIRST column in the prices matrix of the third item in the original list, 1 2 3 just for the illustration purposes
  ..$ lower   : num -0.96
  ..$ midpoint: num 1
  ..$ upper   : num 2.96
 $ :List of 4
  ..$ prices  : num [1:5] 1 2 3 ... #This should be the SECOND column in the prices matrix of the third item in the original list, 1 2 3 ... just for the illustration purposes
  ..$ lower   : num -0.04
  ..$ midpoint: num 2
  ..$ upper   : num 3.96
 $ :List of 4
  ..$ prices  : num [1:5] 1 2 3 ... #This should be the THIRD column in the prices matrix of the third item in the original list, 1 2 3 ... just for the illustration purposes
  ..$ lower   : num 1.04
  ..$ midpoint: num 3
  ..$ upper   : num 4.96
 $ :List of 4
  ..$ prices  : num [1:5] 6.78 -0.28 2.565 0.553 14.275
  ..$ lower   : num -4.84
  ..$ midpoint: num 3
  ..$ upper   : num 10.8

有没有比开始在 for 循环中填充新列表更好的方法,以便:

newlist <- list()
newlist_i <- 1 #This index increases faster than i, whenever we encounter a "compressed" list item.
for(i in 1:length(origlist)) {
    if(!is.null(dim(origlist[[i]]$prices)) { #dim(vector) returns NULL
        for(j in 1:ncol(prices)) {
            newlist[[newlist_i+j-1]]$prices <- origlist[[i]]$prices[,j]
            newlist[[newlist_i+j-1]]$lower <- origlist[[i]]$lower[j]
            newlist[[newlist_i+j-1]]$midpoint <- origlist[[i]]$midpoint[j]
            newlist[[newlist_i+j-1]]$upper <- origlist[[i]]$upper[j]
        }
        newlist_i = newlist_i + dim(origlist[[i]]$prices) - 1
    } else {
        newlist[[i]] <- origlist[[i]]
        newlist_i = newlist_i + 1
    }
}

但是for循环看起来非常丑陋和复杂。有没有更好的方法可以做到这一点?

r list 循环 for 循环

评论

2赞 margusl 10/10/2023
请将输出包含在您的问题中。dput(origlist)
1赞 Aku-Ville Lehtimäki 10/11/2023
@margusl,这是一个有效的观点,我的错误,很抱歉。这本来是问题的一个重要部分。

答:

1赞 asd-tm 10/11/2023 #1

我将提供以下基本 R 解决方案:

do.call(rbind, 
        lapply(my_d, \(x){
          rbind(x$prices |> matrix(5), x$lower, x$midpoint, x$upper) |> t()
        }) 
) |> apply(MARGIN = 1, \(x) {
  list(
  prices = x[1:5],
  lower = x[6],
  midpoint = x[7],
  upper = x[8]
  )
})

或者,如果长度未知:prices

do.call(rbind, 
        lapply(my_d, \(x){
          cbind(x$prices |> matrix(length(x$lower), byrow = T), x$lower, x$midpoint, x$upper) 
        }) 
) |> apply(MARGIN = 1, \(x) {
  list(
    prices = x[1:(length(x) - 3)],
    lower = x[length(x) - 2],
    midpoint = x[length(x) - 1],
    upper = x[length(x)]
  )
})

两个脚本返回相同的输出:

[[1]]
[[1]]$prices
[1]  1.9196255  0.1770681  2.3306149 -0.8893725  0.7117880

[[1]]$lower
[1] 1.317551

[[1]]$midpoint
[1] 0.4215168

[[1]]$upper
[1] -0.8721538


[[2]]
[[2]]$prices
[1] -1.0674630  0.2179483 -2.2493795  0.2747926 -1.3451170

[[2]]$lower
[1] 1.444299

[[2]]$midpoint
[1] 1.212617

[[2]]$upper
[1] 0.1006223


[[3]]
[[3]]$prices
[1] -0.3124539  0.8772849  0.4090815  0.4909305 -0.9445474

[[3]]$lower
[1] -1.182347

[[3]]$midpoint
[1] -1.285585

[[3]]$upper
[1] -1.537147


[[4]]
[[4]]$prices
[1] -0.6609199  0.2626416 -0.2137965 -0.2261824 -0.8723562

[[4]]$lower
[1] -1.693114

[[4]]$midpoint
[1] -1.607736

[[4]]$upper
[1] -0.05325191


[[5]]
[[5]]$prices
[1] -0.8811282 -0.8030718  2.4720077 -0.1622402  0.9657835

[[5]]$lower
[1] -0.4743322

[[5]]$midpoint
[1] -0.9583107

[[5]]$upper
[1] 0.264364


[[6]]
[[6]]$prices
[1] -0.1863864  0.2615337 -0.3725853 -0.1614547  0.4465152

[[6]]$lower
[1] 0.03844349

[[6]]$midpoint
[1] -0.5716921

[[6]]$upper
[1] -1.85495

使用数据:

my_d <- list(
  list(prices = rnorm(5),
       lower = rnorm(1),
       midpoint = rnorm(1),
       upper = rnorm(1)),
  list(prices = rnorm(5),
       lower = rnorm(1),
       midpoint = rnorm(1),
       upper = rnorm(1)),
  list(prices = matrix(rnorm(5*3), 5),
       lower = rnorm(3),
       midpoint = rnorm(3),
       upper = rnorm(3)),
  list(prices = rnorm(5),
       lower = rnorm(1),
       midpoint = rnorm(1),
       upper = rnorm(1))
)
1赞 Onyambu 10/11/2023 #2

您可以使用 + + 使用 @asd-tm 中的数据(在到期时给予积分)ModifyListasplitlapply

origlist <- md

lapply(origlist, \(x)
  if(length(dim(x$prices))) 
    do.call(Map, c(list,modifyList(x, list(prices = asplit(x$prices,2)))))
  else list(x)
)|>unlist(FALSE)

List of 6
 $ :List of 4
  ..$ prices  : num [1:5] 1.097 0.435 -0.326 1.149 0.994
  ..$ lower   : num 0.548
  ..$ midpoint: num 0.239
  ..$ upper   : num -0.628
 $ :List of 4
  ..$ prices  : num [1:5] 1.361 -0.6 2.187 1.533 -0.236
  ..$ lower   : num -1.03
  ..$ midpoint: num -0.71
  ..$ upper   : num 0.257
 $ :List of 4
  ..$ prices  : num [1:5(1d)] -0.247 -0.348 -0.952 -0.045 -0.785
  ..$ lower   : num -0.641
  ..$ midpoint: num 0.118
  ..$ upper   : num -0.256
 $ :List of 4
  ..$ prices  : num [1:5(1d)] -1.668 -0.38 0.919 -0.575 0.608
  ..$ lower   : num -0.85
  ..$ midpoint: num -0.947
  ..$ upper   : num 1.84
 $ :List of 4
  ..$ prices  : num [1:5(1d)] -1.6179 -0.0556 0.5194 0.3012 0.1057
  ..$ lower   : num -1.02
  ..$ midpoint: num -0.491
  ..$ upper   : num -0.652
 $ :List of 4
  ..$ prices  : num [1:5] 0.2354 0.078 -0.9619 -0.0713 1.4446
  ..$ lower   : num 0.452
  ..$ midpoint: num 0.0412
  ..$ upper   : num -0.422