Вставить список в вектор, повторяя список для каждого векторного уровня
Я хочу выполнить следующую задачу, не вводя for
петля, а точнее в одном apply()
команда.
У меня есть список a
что я хочу повторить N
раз, где N
длина вектора b
вставляя каждое повторение a
к элементу b
,
До сих пор я сделал следующее MWE:
var <- paste("var", 1:4, sep="")
treat <- c("A","B")
spec <- paste("sp", 1:3, sep="")
a <- combn(var, 2, simplify = FALSE)#this 6 times, for each treatment and species
b <- do.call(paste, c(expand.grid(treat, spec), sep='.'))
a1 <- lapply(a, paste, b[1], sep='.')
a2 <- lapply(a, paste, b[2], sep='.')
a3 <- lapply(a, paste, b[3], sep='.')
a4 <- lapply(a, paste, b[4], sep='.')
a5 <- lapply(a, paste, b[5], sep='.')
a6 <- lapply(a, paste, b[6], sep='.')
a.final <- c(a1,a2,a3,a4,a5,a6)
a.final
Было бы оптимальным, если бы я мог вставить b
до a
,
Обратите внимание, что мои отправные точки - 3 вектора: var
, treat
а также spec
так что не стесняйтесь менять что-либо с этого момента.
3 ответа
Вариант 1: мы можем сделать это без каких-либо apply()
петли на всех. Давайте unlist()
a
список, paste()
это реплицируется b
значения, то relist()
это основано на реплицированных a
списки. Попробуй это:
aa <- relist(
paste(unlist(a), rep(b, each=sum(lengths(a))), sep="."),
rep.int(a, length(b))
)
Проверьте:
identical(aa, a.final)
# [1] TRUE
Вариант 1 с b
до a
: Теперь, чтобы поставить b
значения впереди, просто поменяйте местами аргументы в paste()
вызов:
relist(
paste(rep(b, each=sum(lengths(a))), unlist(a), sep = "."),
rep.int(a, length(b))
)
Вариант 2: эта опция использует apply()
петля. Здесь мы используем Map()
сделать вставку один на один.
ra <- rep(a, length(b))
aa2 <- Map(paste, ra, relist(rep(b, each=sum(lengths(a))), ra), sep = ".")
Проверьте:
identical(aa2, a.final)
# [1] TRUE
Вариант 2 с b
до a
: Просто поменять неназванный Map()
аргументы, которые передаются paste()
,
ra <- rep(a, length(b))
Map(paste, relist(rep(b, each=sum(lengths(a))), ra), ra, sep = ".")
Оставаясь близко к подходу ОП, это можно решить с помощью вложенных lapply()
используя анонимные функции:
unlist(lapply(b, function(x) lapply(a, function(y) paste(x, y, sep = "."))),
recursive = FALSE)
[[1]] [1] "A.sp1.var1" "A.sp1.var2" [[2]] [1] "A.sp1.var1" "A.sp1.var3" [[3]] [1] "A.sp1.var1" "A.sp1.var4" ... [[34]] [1] "B.sp3.var2" "B.sp3.var3" [[35]] [1] "B.sp3.var2" "B.sp3.var4" [[36]] [1] "B.sp3.var3" "B.sp3.var4"
Заметка, b
наклеивается перед a
, unlist()
требуется, чтобы сгладить список верхнего уровня.
Для проверки подход работает (a
перед b
сравнить с a.final
):
identical(a.final,
unlist(lapply(b, function(x) lapply(a, function(y) paste(y, x, sep = "."))),
recursive = FALSE))
[1] TRUE
Это совершенно другой подход, который создает метки с нуля и возвращает их в таблице данных размером 36 строк и 2 столбца вместо списка с 36 векторами длины 2:
library(data.table)
# cross join of treat, spec, var. Note, full labels will be created in sprintf() below
DT <- CJ(LETTERS[1:2], 1:3, 1:4)
# non equi join as replacement of combn()
DT[DT, on = .(V1, V2, V3 > V3), nomatch = 0L,
# create labels
.(sprintf("%s.sp%s.var%i", V1, V2, V3),
sprintf("%s.sp%s.var%i", V1, V2, x.V3))]
V1 V2 1: A.sp1.var1 A.sp1.var2 2: A.sp1.var1 A.sp1.var3 3: A.sp1.var1 A.sp1.var4 4: A.sp1.var2 A.sp1.var3 5: A.sp1.var2 A.sp1.var4 6: A.sp1.var3 A.sp1.var4 7: A.sp2.var1 A.sp2.var2 ... 29: B.sp2.var2 B.sp2.var4 30: B.sp2.var3 B.sp2.var4 31: B.sp3.var1 B.sp3.var2 32: B.sp3.var1 B.sp3.var3 33: B.sp3.var1 B.sp3.var4 34: B.sp3.var2 B.sp3.var3 35: B.sp3.var2 B.sp3.var4 36: B.sp3.var3 B.sp3.var4 V1 V2