均衡列表中所有列表的长度?

时间:2017-04-14 16:34:20

标签: r list

我有一个列表列表,我希望子列表都具有相同的长度

即。如果需要,用NA填充它们,以便它们都达到最长列表的长度。

模拟示例

list1 <- list(1, 2, 3)
list2 <- list(1, 2, 3, 4, 5)
list3 <- list(1, 2, 3, 4, 5, 6)

list_lists <- list(list1, list2, list3)

我最好的尝试

max_length <- max(unlist(lapply (list_lists, FUN = length))) 
    # returns the length of the longest list

list_lists <- lapply (list_lists, function (x) length (x) <- max_length)

问题是,它将我的所有子列表替换为整数= max_length ...

list_lists [[1]]
> [1] 6

有人可以帮忙吗?

5 个答案:

答案 0 :(得分:5)

试试这个(ls是你的清单):

lapply(lapply(sapply(ls, unlist), "length<-", max(lengths(ls))), as.list)

答案 1 :(得分:3)

这是您的代码已修复。 该函数应返回x,而不是length(x)。 另外,为了清晰起见,我使用了矢量而不是列表。

list1 <- c(1, 2, 3)
list2 <- c(1, 2, 3, 4, 5)
list3 <- c(1, 2, 3, 4, 5, 6)

list_lists <- list(list1, list2, list3)

max_length <- max(unlist(lapply (list_lists, FUN = length))) 

list_lists <- lapply (list_lists, function (x) {length (x) <- max_length;x})

# [[1]]
# [1]  1  2  3 NA NA NA
# 
# [[2]]
# [1]  1  2  3  4  5 NA
# 
# [[3]]
# [1] 1 2 3 4 5 6

对于原始列表,结果为:

# [[1]]
# [[1]][[1]]
# [1] 1
# 
# [[1]][[2]]
# [1] 2
# 
# [[1]][[3]]
# [1] 3
# 
# [[1]][[4]]
# NULL
# 
# [[1]][[5]]
# NULL
# 
# [[1]][[6]]
# NULL
# 
# 
# [[2]]
# [[2]][[1]]
# [1] 1
# 
# [[2]][[2]]
# [1] 2
# 
# [[2]][[3]]
# [1] 3
# 
# [[2]][[4]]
# [1] 4
# 
# [[2]][[5]]
# [1] 5
# 
# [[2]][[6]]
# NULL
# 
# 
# [[3]]
# [[3]][[1]]
# [1] 1
# 
# [[3]][[2]]
# [1] 2
# 
# [[3]][[3]]
# [1] 3
# 
# [[3]][[4]]
# [1] 4
# 
# [[3]][[5]]
# [1] 5
# 
# [[3]][[6]]
# [1] 6

答案 2 :(得分:3)

在列表中,NULL似乎比NA更合适,并且可以添加vector

list_lists <- list(list(1, 2, 3),
                   list(1, 2, 3, 4, 5),
                   list(1, 2, 3, 4, 5, 6))


list_lists2 <- Map(function(x, y){c(x, vector('list', length = y))}, 
                   list_lists, 
                   max(lengths(list_lists)) - lengths(list_lists))

str(list_lists2)
#> List of 3
#>  $ :List of 6
#>   ..$ : num 1
#>   ..$ : num 2
#>   ..$ : num 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>  $ :List of 6
#>   ..$ : num 1
#>   ..$ : num 2
#>   ..$ : num 3
#>   ..$ : num 4
#>   ..$ : num 5
#>   ..$ : NULL
#>  $ :List of 6
#>   ..$ : num 1
#>   ..$ : num 2
#>   ..$ : num 3
#>   ..$ : num 4
#>   ..$ : num 5
#>   ..$ : num 6

如果您真的需要NA,只需将vector更改为rep

list_lists3 <- Map(function(x, y){c(x, rep(NA, y))}, 
                   list_lists, 
                   max(lengths(list_lists)) - lengths(list_lists))

str(list_lists3)
#> List of 3
#>  $ :List of 6
#>   ..$ : num 1
#>   ..$ : num 2
#>   ..$ : num 3
#>   ..$ : logi NA
#>   ..$ : logi NA
#>   ..$ : logi NA
#>  $ :List of 6
#>   ..$ : num 1
#>   ..$ : num 2
#>   ..$ : num 3
#>   ..$ : num 4
#>   ..$ : num 5
#>   ..$ : logi NA
#>  $ :List of 6
#>   ..$ : num 1
#>   ..$ : num 2
#>   ..$ : num 3
#>   ..$ : num 4
#>   ..$ : num 5
#>   ..$ : num 6

请注意,后者中的类型不会匹配,除非您指定NA_real_或强制NA以匹配x的类型。

答案 3 :(得分:2)

试试这个:

funJoeOld <- function(ls) {
    list_length <- sapply(ls, length)
    max_length <- max(list_length)

    lapply(seq_along(ls), function(x) {
        if (list_length[x] < max_length) {
            c(ls[[x]], lapply(1:(max_length - list_length[x]), function(y) NA))
        } else {
            ls[[x]]
        }
    })
}

funJoeOld(list_lists)[[1]]
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[[4]]
[1] NA

[[5]]
[1] NA

[[6]]
[1] NA


修改

只是想说明如何使用R中的正确工具产生巨大的变化。虽然我的解决方案给出了正确的结果,但效率非常低。将sapply(ls, length)替换为lengths以及将lapply(1:z, function(y) NA)替换为as.list(rep(NA, z)),我们可以获得近15倍的加速速度。观察:

funJoeNew <- function(ls) {
    list_length <- lengths(ls)
    max_length <- max(list_length)

    lapply(seq_along(ls), function(x) {
        if (list_length[x] < max_length) {
            c(ls[[x]], as.list(rep(NA, max_length - list_length[x])))
        } else {
            ls[[x]]
        }
    })
}

funAlistaire <- function(ls) {
    Map(function(x, y){c(x, rep(NA, y))}, 
        ls, 
        max(lengths(ls)) - lengths(ls))
}

fun989 <- function(ls) {
    lapply(lapply(sapply(ls, unlist), "length<-", max(lengths(ls))), as.list)
}

比较平等

set.seed(123)
samp_list <- lapply(sample(1000, replace = TRUE), function(x) {lapply(1:x, identity)})

## have to unlist as the NAs in 989 are of the integer
## variety and the NAs in Joe/Alistaire are logical
identical(sapply(fun989(samp_list), unlist), sapply(funJoeNew(samp_list), unlist))
[1] TRUE

identical(funJoeNew(samp_list), funAlistaire(samp_list))
[1] TRUE

<强>基准

microbenchmark(funJoeOld(samp_list), funJoeNew(samp_list), fun989(samp_list),
                             funAlistaire(samp_list), times = 30, unit = "relative")
Unit: relative
                expr       min        lq      mean    median        uq       max neval cld
funJoeOld(samp_list) 21.825878 23.269846 17.434447 20.803035 18.851403 4.8056784    30   c
funJoeNew(samp_list)  1.827741  1.841071  2.253294  1.667047  1.780324 2.4659653    30 ab 
   fun989(samp_list)  3.108230  3.563780  3.170320  3.790048  3.888632 0.9890681    30  b 
   funAli(samp_list)  1.000000  1.000000  1.000000  1.000000  1.000000 1.0000000    30 a  

这里有两个收获:

  1. apply函数族有一个很好的理解 简洁高效的代码(可以在@ alistaire和@ 989的解决方案中看到)。
  2. 了解base R的细微差别一般会产生相当大的后果

答案 4 :(得分:1)

不确定您是否在寻找此项,并且您可以将lengths功能用于列表:

list_lists <- list(unlist(list1), unlist(list2), unlist(list3))
list_lists1 <- lapply(list_lists, `length<-`, max(lengths(list_lists)))
list_lists1

    > list_lists1
[[1]]
[1]  1  2  3 NA NA NA

[[2]]
[1]  1  2  3  4  5 NA

[[3]]
[1] 1 2 3 4 5 6

对于列表列表,您可以更进一步:

list_lists2 <- lapply(list_lists1,as.list)


> list_lists2
[[1]]
[[1]][[1]]
[1] 1

[[1]][[2]]
[1] 2

[[1]][[3]]
[1] 3

[[1]][[4]]
[1] NA

[[1]][[5]]
[1] NA

[[1]][[6]]
[1] NA


[[2]]
[[2]][[1]]
[1] 1

[[2]][[2]]
[1] 2

[[2]][[3]]
[1] 3

[[2]][[4]]
[1] 4

[[2]][[5]]
[1] 5

[[2]][[6]]
[1] NA


[[3]]
[[3]][[1]]
[1] 1

[[3]][[2]]
[1] 2

[[3]][[3]]
[1] 3

[[3]][[4]]
[1] 4

[[3]][[5]]
[1] 5

[[3]][[6]]
[1] 6


>