1) igraph
Мы можем преобразовать x
, показанное в примечании в конце, в igraph g
, а затем igraph выполнит с ним множество операций.
library(igraph)
DF <- data.frame(parent = sub("\\.\\d+$", "", x), name = x, stringsAsFactors = FALSE)
DF <- subset(DF, parent != name) # remove loop in root to itself
g <- graph.data.frame(DF)
Parent
node <- "1.1"
setdiff(names(subcomponent(g, node, mode = "in")), node)
## [1] "1"
Потомки узла
node <- "1.2"
setdiff(names(neighborhood(g, nodes = node, mode = "out")[[1]]), node)
## [1] "1.2.1" "1.2.2"
Все потомки узла
node <- "1.2"
setdiff(names(subcomponent(g, node, mode = "out")), node)
## [1] "1.2.1" "1.2.2" "1.2.1.2" "1.2.1.1" "1.2.2.1" "1.2.2.2"
## [7] "1.2.1.2.1"
Глубина каждого узла
dfs(g, root = "1", dist = TRUE)$dist
## 1 1.1 1.1.1 1.1.3 1.2 1.2.1 1.2.1.2 1.2.2
## 0 1 2 2 1 2 3 2
## 1.1.1.1 1.1.2 1.1.3.1 1.1.3.2 1.1.3.3 1.2.1.1 1.2.1.2.1 1.2.2.1
## 3 2 3 3 3 3 4 3
## 1.2.2.2
## 3
Листьев
names(which(degree(g, mode = "out") == 0))
## [1] "1.1.1.1" "1.1.2" "1.1.3.1" "1.1.3.2" "1.1.3.3" "1.2.1.1"
## [7] "1.2.1.2.1" "1.2.2.1" "1.2.2.2"
График
plot(g, layout = layout_as_tree(g))
(продолжение после графика)
![screenshot](https://i.stack.imgur.com/6GSZR.png)
Мы также можем использовать пакет rviewgraph:
library(rviewgraph)
rViewGraph(g)
2) строки
Используя x
из примечания в конце, мы можем применить к нему обычные строковые операции напрямую, так что, возможно, нет необходимости преобразовывать данные вообще .
Непосредственные дочерние элементы данного узла
parent <- "1"
pat <- sprintf("^%s\\.\\d+$", parent)
grep(pat, x, value = TRUE)
## [1] "1.1" "1.2"
Все узлы заданной глубины
depth <- 2
pat2 <- sprintf("^\\d+(\\.\\d+){%d}$", depth-1)
grep(pat2, x, value = TRUE)
[1] "1.1" "1.2"
или
depth <- 2
pat2 <- sprintf("^%s$", paste(rep("\\d+", depth), collapse = "\\."))
grep(pat2, x, value = TRUE)
## [1] "1.1" "1.2"
Список с одним компонентом на глубина
Каждый компонент перечисляет все узлы на этой глубине.
split(x, nchar(gsub("\\d", "", x)) + 1)
## $`1`
## [1] "1"
##
## $`2`
## [1] "1.1" "1.2"
##
## $`3`
## [1] "1.1.1" "1.1.2" "1.1.3" "1.2.1" "1.2.2"
##
## $`4`
## [1] "1.1.1.1" "1.1.3.1" "1.1.3.2" "1.1.3.3" "1.2.1.1" "1.2.1.2" "1.2.2.1"
## [8] "1.2.2.2"
##
## $`5`
## [1] "1.2.1.2.1"
Родитель данного узла
Мы можем опустить строку, отмеченную ##, если это нормально иметь root п ode быть его собственным родителем.
node <- "1.1"
parent <- sub("\\.\\d+$", "", node)
parent <- setdiff(parent, node) ##
parent
## [1] "1"
Братья и сестры данного узла
Получить потомков родителя, а затем удалить входной узел из этого результата.
node <- "1.1"
parent <- sub("\\.\\d+$", "", node)
pat <- sprintf("^%s\\.\\d+$", parent)
setdiff(grep(pat, x, value = TRUE), node)
## [1] "1.2"
Все потомки данный узел
node <- "1.2"
x[startsWith(x, paste0(node, "."))]
## [1] "1.2.1" "1.2.1.1" "1.2.1.2" "1.2.1.2.1" "1.2.2" "1.2.2.1"
## [7] "1.2.2.2"
Все предки данного узла
node <- "1.2.1"
x[startsWith(node, paste0(x, "."))]
## [1] "1" "1.2"
Листовые узлы
leaf <- x[sapply(x, function(st) sum(startsWith(x, st))) == 1]
leaf
## [1] "1.1.1.1" "1.1.2" "1.1.3.1" "1.1.3.2" "1.1.3.3" "1.2.1.1"
## [7] "1.2.1.2.1" "1.2.2.1" "1.2.2.2"
Внутренние узлы
setdiff(x, leaf)
## [1] "1" "1.1" "1.1.1" "1.1.3" "1.2" "1.2.1" "1.2.1.2"
## [8] "1.2.2"
Примечание
x <- c("1", "1.1", "1.1.1", "1.1.1.1", "1.1.2", "1.1.3", "1.1.3.1",
"1.1.3.2", "1.1.3.3", "1.2",
"1.2.1", "1.2.1.1", "1.2.1.2", "1.2.1.2.1", "1.2.2", "1.2.2.1", "1.2.2.2")