【问题标题】:interleave list after every n elements每 n 个元素后交错列表
【发布时间】:2018-03-22 10:26:58
【问题描述】:

我想在每 2 个列表元素之后交错 interElem

数据:

listi     <- c(rbind(letters[1:4], list(c(13,37))))

interElem <- c("inter","leavistan")

看起来像:

> listi
[[1]]
[1] "a"

[[2]]
[1] 13 37

[[3]]
[1] "b"

[[4]]
[1] 13 37

[[5]]
[1] "c"

[[6]]
[1] 13 37

[[7]]
[1] "d"

[[8]]
[1] 13 37

> 

想要的结果(列表元素编号不准确)

> listi
[[1]]
[1] "a"

[[2]]
[1] 13 37

[[XXX]]
[1] "inter" "leavistan"

[[3]]
[1] "b"

[[4]]
[1] 13 37

[[XXX]]
[1] "inter" "leavistan"

[[5]]
[1] "c"

[[6]]
[1] 13 37

[[XXX]]
[1] "inter" "leavistan"

[[7]]
[1] "d"

[[8]]
[1] 13 37

> 

【问题讨论】:

    标签: r list interleave


    【解决方案1】:

    这是新列表的长度

    len = length(listi) + max(0, floor((length(listi) - 1) / 2))
    

    以及应该是原始值的元素的索引

    idx = seq_len(len) %% 3 != 0
    

    使用这些来创建新列表并插入旧值和间隙值

    res = vector("list", len)
    res[idx] = l
    res[!idx] = list(v)
    

    将包作为一个函数来实现健壮性和重用。

    fun = function(l, v, n = 2) {
        ## validate arguments
        stopifnot(
            is.numeric(n), length(n) == 1, !is.na(n),
            is.list(l), is.vector(v)
        )
    
        ## length and index for original values
        len = length(l) + max(0, floor((length(l) - 1) / n))
        idx = seq_len(len) %% (n + 1) != 0
    
        ## create and populate result
        res = vector("list", len)
        res[idx] = l
        res[!idx] = list(v)
        res
    }
    

    > str(fun(listi, interElem))
    List of 11
     $ : chr "a"
     $ : num [1:2] 13 37
     $ : chr [1:2] "inter" "leavistan"
     $ : chr "b"
     $ : num [1:2] 13 37
     $ : chr [1:2] "inter" "leavistan"
     $ : chr "c"
     $ : num [1:2] 13 37
     $ : chr [1:2] "inter" "leavistan"
     $ : chr "d"
     $ : num [1:2] 13 37
    

    【讨论】:

    • 你的功能很好用。然而它不适用于 n=3:Error: length(l)%%n == 0 is not TRUE 我明白你为什么省略它。但最好也有不平衡的交错。
    • 我可以在 stopifnot 中注释掉length(l) %% n == 0 部分,我得到一个通用的解决方案!
    • @AndreElrico 我更新了计算最终列表长度的方式,因此它适用于任何输入列表。
    【解决方案2】:

    我们可以创建一个分组变量,用gl 分割每两个元素,然后在每个嵌套的list 末尾附加“interElem”,并用do.call(c 将其展平

    res <- head(do.call(c, lapply(split(listi, as.integer(gl(length(listi), 2, 
               length(listi)))), function(x) c(x, list(interElem )))), -1)
    names(res) <- NULL
    

    或者另一种选择是将其转换为 matrixrbind 与 'interElem' 并连接到 list

    head(c(rbind(matrix(listi, nrow=2), list(interElem))), -1)
    #[[1]]
    #[1] "a"
    
    #[[2]]
    #[1] 13 37
    
    #[[3]]
    #[1] "inter"     "leavistan"
    
    #[[4]]
    #[1] "b"
    
    #[[5]]
    #[1] 13 37
    
    #[[6]]
    #[1] "inter"     "leavistan"
    
    #[[7]]
    #[1] "c"
    
    #[[8]]
    #[1] 13 37
    
    #[[9]]
    #[1] "inter"     "leavistan"
    
    #[[10]]
    #[1] "d"
    
    #[[11]]
    #[1] 13 37
    

    或者我们可以在for 循环中使用append

    listn <- listi
    i1 <- seq(2, length(listi), by = 2)
    i2 <- i1 + (seq_along(i1) - 1)
    for(i in seq_along(i2)) listn <-  append(listn, list(interElem), after = i2[i])
    head(listn, -1)
    

    【讨论】:

    • 嘿,当n = 3 时,您的第二个解决方案有回收效果。其他的工作就像一个魅力。
    • @AndreElrico 是的,这是真的。这不是通用解决方案,而是针对此示例的修复
    【解决方案3】:

    这适用于您的示例和奇数长度的列表,包括 2 和 1。如果列表的长度是奇数,matrix()cbind() 会发出警告。空列表作为条目返回插入列表。我在这里要做的就是为聚合的listilist(interElem)的以下子集形成索引向量。

    l <- length(listi)
    i <- rbind(matrix(1:l, nrow = 2), rep(l+1,l%/%2))[1:(l + l%/%2 - (l+1)%%2)]
    c(listi, list(interElem))[i]
    

    【讨论】:

      猜你喜欢
      • 2020-03-12
      • 2015-09-11
      • 2020-11-05
      • 2018-03-11
      • 2012-09-21
      • 2017-08-22
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      相关资源
      最近更新 更多