Чередовать список после каждого n элементов

Я хочу чередовать interElem после каждых 2 элементов списка.

Данные:

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

> 

3 ответа

Решение

Вот длина нового списка

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

Мы можем создать переменную группировки, чтобы разделить каждые 2 элемента gl, затем добавьте 'interElem' в конце каждого вложенного list и сгладить его 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

Или другой вариант, чтобы преобразовать его в matrix, rbind с 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

Или мы можем использовать append в for петля

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)

Это работает на вашем примере и в списках с нечетной длиной, включая 2 и 1. Если длина списка нечетная, matrix() а также cbind() предупреждения о повышении Пустой список как запись возвращает список вставки. Все, что я пытаюсь сделать здесь, это сформировать вектор индексов для последующего поднабора агрегированных listiа также list(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]
Другие вопросы по тегам