rlistinterleave

interleave list after every n elements


I want to interleave interElem after every 2 list elements.

Data:

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

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

looks like:

> 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

> 

Desired result (list element numbers are not accurate)

> 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

> 

Solution

  • Here's the length of the new list

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

    and the index of the elements that should be the original values

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

    Use these to create a new list and insert the old and interstitial values

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

    Package as a function for robustness and reuse.

    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
    }
    

    with

    > 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