r - R - 从另一个列表上的操作填充一个空列表
问题描述
我正在编写一个 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 中非常慢。我的实际问题可能会有 100 或 1000 个查询词和更多的祖先词。所以 lst 会很长。所以我认为 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"
希望这可以帮助!
推荐阅读
- php - 获取数据库中 item_type 的值并在选项中选择它
- javascript - 重新加载 DOMContent
- tsql - MSSQL IP 地址更新为二进制 (32)
- javascript - 使用变量而不是值更改键名
- docker - 如何在没有 JAR 的情况下为 Spring Boot 应用程序构建 Docker 映像
- mapbox - Mapbox GL JS:更改多边形边框宽度
- java - 打开 Selenium 浏览器的方法不与我当前的浏览器重叠
- c - 如何使用双指针释放树结构?
- powerbi - 基于切片器的动态存储桶
- reactjs - 在重定向外部 JS 在 react-router-dom 中不起作用