Сначала ваши данные:
l = list(
c("#solarpanels", "#solar"),
c("#Nuclear", "#Wind", "#solar"),
"#solar",
c("#steel", "#windenergy", "#solarenergy", "#carbonfootprint"),
c("#solar", "#wind")
)
Вот двухстрочная версия:
l = l[lengths(l) > 1L]
data.frame(do.call(rbind, unlist(lapply(l, combn, 2L, simplify = FALSE), recursive = FALSE)))
# X1 X2
# 1 #solarpanels #solar
# 2 #Nuclear #Wind
# 3 #Nuclear #solar
# 4 #Wind #solar
# 5 #steel #windenergy
# 6 #steel #solarenergy
# 7 #steel #carbonfootprint
# 8 #windenergy #solarenergy
# 9 #windenergy #carbonfootprint
# 10 #solarenergy #carbonfootprint
# 11 #solar #wind
Медленнее, для ясности:
combn(x, k)
возвращает все возможные (неупорядоченное) подмножество размера k
из x
; то, что вы ищете, это пары из каждого элемента списка. По умолчанию он возвращает это как matrix
со столбцами p = choose(length(x), k)
, но это не очень полезный формат для вашего случая использования; simplify = FALSE
возвращает каждое подмножество как новый элемент list
.
Так что lapply(l, combn, 2L, simplify = FALSE)
будет выглядеть примерно так:
# [[1]]
# [[1]][[1]]
# [1] "#solarpanels" "#solar"
#
#
# [[2]]
# [[2]][[1]]
# [1] "#Nuclear" "#Wind"
#
# [[2]][[2]]
# [1] "#Nuclear" "#solar"
(мы должны отфильтровать length-1 сначала элементы l
, так как ошибка запрашивать 2
элементов у объекта длины-1, отсюда и первая строка)
Бит lapply(.)
- суть вашей проблемы; остальное - просто добавление вывода (в котором уже есть все правильные данные) в формат data.frame
.
Во-первых, вывод lapply
является вложенным - это list
из list
s. , Более равномерно иметь list
векторов длины-2; unlist(., recusive=FALSE)
выполняет это путем удаления вложенных списков первого уровня (с recursive=TRUE
мы получим большой длинный вектор и потеряем парную структуру; мы могли бы работать с этим, но я думаю, что это может быть немного неестественно) .
Далее мы превращаем список векторов длины 2 в матрицу (с учетом конечной цели - матрицу из 2 столбцов очень легко преобразовать в data.frame
); list
-> matrix
выполняется в base
с do.call(rbind, .)
.
Наконец мы передаем это data.frame
, et voila !
В data.table
я бы сделал это немного чище и в одной команде:
setDT(transpose(
unlist(lapply(l[lengths(l) > 1L], combn, 2L, simplify = FALSE), recursive = FALSE)
))[]
Учитывая, что вы, вероятно, не очень заботитесь о промежуточном выводе, это было бы также неплохо использовать magrittr
:
library(magrittr)
l[lengths(l) > 1L] %>%
lapply(combn, 2L, simplify = FALSE) %>%
unlist(recursive = FALSE) %>%
do.call(rbind, . ) %>%
data.frame
Это более читабельно, но в этом случае было бы неплохо увидеть, что data.frame
является конечной целью заранее, так как в противном случае намерение шагов unlist
& do.call
может быть неясным.