Я пишу программу R для анализа древовидной структуры. В моем примере ниже в дереве 10 узлов, и предки каждого узла (родители этого узла и родители родителей этого узла и т. д.) хранятся в списке под названием Ancestors. Пользователь будет запрашивать вектор имен узлов, и я пытаюсь создать список, который будет заполнен предками этого запроса. Каждый элемент в списке будет содержать список потомков запроса для каждого из вызываемых предков. Пожалуйста, смотрите ниже для примера
Допустим, у меня есть следующая структура.
Таким образом, список предков будет выглядеть так.
Ancestors <- list()
Ancestors$'p1' <- c('p2', 'p3', 'p4', 'p5', 'p8', 'p9', 'p10')
Ancestors$'p2' <- c('p4', 'p5', 'p8', 'p9', 'p10')
Ancestors$'p3' <- c('p4', 'p5', 'p9', 'p10')
Ancestors$'p4' <- c('p5', 'p9', 'p10')
Ancestors$'p5' <- c('p9', 'p10')
Ancestors$'p6' <- c('p4', 'p5', 'p9', 'p10')
Ancestors$'p7' <- c('p5', 'p9', 'p10')
Ancestors$'p8' <- c('p5', 'p9', 'p10')
Ancestors$'p9' <- NA
Ancestors$'p10' <- NA
Допустим, запрос
query <- c('p5', 'p4', 'p1')
Тогда список, который я хотел бы создать,
# lst <- list()
#
# lst$'p2'
# 'p1'
# lst$'p3'
# 'p1'
# lst$'p4'
# 'p1'
# lst$'p5'
# 'p1', 'p4'
# lst$'p8'
# 'p1'
# lst$'p9'
# 'p1', 'p4', 'p5'
# lst$'p10'
# 'p1', 'p4', 'p5'
(2,3,4,5,8,9,10) — это все предки, существующие для терминов запроса. Вот список, который я хотел бы составить. Затем для каждого из этих именованных элементов я хотел бы составить список терминов запроса, которые являются потомками элемента списка. Прошу прощения за запутанный пример. Я надеюсь, что это имеет смысл.
Вот что я пробовал до сих пор
lst <- list()
lapply(query, function(x) {
theAncestors <- Ancestors[[x]]
sapply(theAncestors, function(y) {
lst[[y]][[1]] <- c(lst[[y]][[1]], x)
})
})
Но это не заполняет список lst. Все, что происходит, это то, что он распечатывает
[[1]]
p9 p10
"p5" "p5"
[[2]]
p5 p9 p10
"p4" "p4" "p4"
[[3]]
p2 p3 p4 p5 p8 p9 p10
"p1" "p1" "p1" "p1" "p1" "p1" "p1"
что немного отличается от того, что я хочу. Кроме того, когда я пытаюсь вывести lst, он все еще пуст. Так что этот код даже не влияет на lst. Итак, как я могу получить желаемый результат? Я думал об использовании цикла for, но я думаю, что он очень медленный в R. Моя реальная проблема, вероятно, будет состоять из сотен или тысяч терминов запроса и многих других терминов-предков. Так что это будет очень долго. Поэтому я думаю, что цикл for, вероятно, не сработает.
Редактировать: я понял это. Мой код сейчас:
lst <- list()
aLst <- unlist(lapply(query, function(x) {
theAncestors <- Ancestors[[x]]
sapply(theAncestors, function(y) {
lst[[y]][1] <- c(lst[[y]][[1]], x)
})
}))
aLst <- split(unname(aLst), names(aLst))
Это распечатывает
$p10
[1] "p5" "p4" "p1"
$p2
[1] "p1"
$p3
[1] "p1"
$p4
[1] "p1"
$p5
[1] "p4" "p1"
$p8
[1] "p1"
$p9
[1] "p5" "p4" "p1"
что я и хотел





Причина, по которой он просто печатается, заключается в том, что ваш lapply ни к чему не привязан. Причина, по которой он не заполняется lst, немного сложнее и связана с областью действия функции — здесь есть очень подробное объяснение: http://adv-r.had.co.nz/Environments.html#function-envs.
Суть в том, что lst не модифицируется — его копия модифицируется внутри функции, но модифицируется в среде, которая отбрасывается после завершения вызова функции. Есть несколько способов обойти это — первый — использовать <<-, а не <-. Этот оператор «глубокого присваивания» выглядит глубже, чем <-, и будет изменять вещи за пределами области действия функции.
Во-вторых, я думаю, что нужно немного по-другому подойти к вашей проблеме - взяв ваш список Ancestors и query вы могли бы сначала сделать:
query_members <- Ancestors[query]
query_members
# $`p4`
# [1] "p5" "p9" "p10"
# $p5
# [1] "p9" "p10"
# $p1
# [1] "p2" "p3" "p4" "p5" "p8" "p9" "p10"
для подмножества элементов, которые вы хотите. Теперь вам нужно «инвертировать» это в некотором смысле. Для начала получите уникальных предков членов вашего запроса:
query_ancestors <- sort(unique(unlist(query_members)))
query_ancestors
# [1] "p10" "p2" "p3" "p4" "p5" "p8" "p9"
Теперь у вас есть то, что вы можете lapply, потому что оно имеет ту же структуру, что и желаемый результат. Вам просто нужно ответить на вопрос «для каждого из этих предков, какой элемент запроса является потомком?»
Таким образом, вы можете написать небольшую функцию, например:
get_descendants <- function(query_ancestor, query_members) {
sort(names(Filter(function(x) { query_ancestor %in% x }, query_members)))
}
# test it out
get_descendants("p5", query_members)
# [1] "p1" "p4"
Теперь мы можем lapply установить имена с помощью нашего query_ancestors:
lst <- lapply(query_ancestors, get_descendants, query_members = query_members)
names(lst) <- query_ancestors
lst
# $`p10`
# [1] "p1" "p4" "p5"
# $p2
# [1] "p1"
# $p3
# [1] "p1"
# $p4
# [1] "p1"
# $p5
# [1] "p1" "p4"
# $p8
# [1] "p1"
# $p9
# [1] "p1" "p4" "p5"
Собрав все вместе, вы могли бы написать хорошую функцию, которая оборачивает все это и позволяет вам сосредоточиться на запросе и списке предков:
list_ancestors <- function(query, Ancestors) {
query_members <- Ancestors[query]
query_ancestors <- sort(unique(unlist(query_members)))
lst <- lapply(query_ancestors, function(element, members) {
sort(names(Filter(function(x) element %in% x, members)))
}, members = query_members)
names(lst) <- query_ancestors
lst
}
# so for example with just p7
list_ancestors("p7", Ancestors)
# $`p10`
# [1] "p7"
# $p5
# [1] "p7"
# $p9
# [1] "p7"
Надеюсь это поможет!
Привет - нет проблем. Если бы мой ответ был полезным и правильным, не могли бы вы принять его в любом случае?
Упс. Ваш ответ было полезен, я просто совсем забыл его принять. Спасибо
Большое спасибо! Я думаю, что ваш способ очень интуитивен, и я буду иметь его в виду, когда столкнусь с подобной проблемой. Но я успел понять это еще до того, как увидел твой пост. См. мое редактирование выше. Спасибо еще раз!