兄弟姐妹和他们的孩子在字符串中的顺序

Avi*_*Avi 2 string r

我用括号格式表示一个树,其中每个级别与其上层分开{.树是二进制的(它可以有一个或两个孩子).我想按字母顺序订购相同级别的兄弟姐妹,同时保留他们的孩子和子孩子.这意味着,只需按字母顺序对每个同级别的2个孩子进行排序.我有一个包含输入树的字符串str1,我想在字符串str2中获得有序.

这是一个例子:

str1<-"{A{C{D{E}}}{B{F{G{H{I}}}}}}"
Run Code Online (Sandbox Code Playgroud)

在订单处理的第一阶段,我希望str2如下:

{A{B{F{G{H{I}}}}}{C{D{E}}}}
Run Code Online (Sandbox Code Playgroud)

只需在C及其所有孩子和B及其所有子孩子之间切换然后继续...(因为C和B都是他们父亲的第二级A.只有一个'{'在B和C之间分开A)我该怎么办?

Fra*_*ank 5

我认为约翰的评论可能在正确的轨道上 - 做你想做的最好的方法,就是把你的字符串转换成适当的面向对象的树结构.随后,您可以将数据操作为树而不是字符串,一旦完成了操作,您可以根据需要将树结构恢复为字符串格式. data.tree我们是一个理想的包装,因为它已经内置了强大的树操作工具(包括一个排序功能),所以没有重新发明轮子.

幸运的是,这种转换在递归时相对容易.以下是将字符串转换为以下内容的代码data.tree:

library(data.tree)

peek.next.node <- function(x){  #Helper function reads the next node (as a string) out of the char vector x
  return(paste(x[2:(which(x=="{"|x=="}")[2]-1)],collapse=""))
}

remove.next.node <- function(x){ #Helper function removes node at the start of the char vector x
  return(x[(which(x=="{"|x=="}")[2]):length(x)])
}

recurse.from.char.vector <- function (x,n){ #inspect input char vector, adding nodes to n if x starts with '{' and returning if x starts with '}'.  Will loop until return
  i<-1
  while(x[1]=="{"){
    new.node.name <- paste(c(peek.next.node(x),"_",i),collapse="")
    child.n <- n$AddChild(new.node.name,label=peek.next.node(x))
    i <- i+1
    x <- remove.next.node(x)
    x <- recurse.from.char.vector(x,child.n)
  }
  return (x[2:length(x)])
}

string.to.tree <- function(x){ #returns head node for a finished tree by calling a recursive parse function
  x.vec <- strsplit(x,"")[[1]]
  head <- Node$new(peek.next.node(x.vec),label = peek.next.node(x.vec))
  recurse.from.char.vector(remove.next.node(x.vec),head) 
  return(head)
}
Run Code Online (Sandbox Code Playgroud)

请注意,即使您的节点标签不止一个字符,此代码也会起作用,并且它也适用于非二叉树.

回到树中的字符串会更容易,因为data.tree对象更自然地适用于递归:

recurse.to.char.vector <- function(n){
  return.vec <-unlist(c("{",n$label))
  if(length(n$children)>0)return.vec <- unlist(c(return.vec,sapply(n$children,recurse.to.char.vector)))
  return.vec <- unlist(c(return.vec,"}"))
  return(return.vec)
}

tree.to.string <- function(n){
  char.vector <- recurse.to.char.vector(n)
  return (paste(char.vector,collapse=""))
}
Run Code Online (Sandbox Code Playgroud)

以下是您的示例:转换,排序和转换回来:

> str1<-"{A{C{D{E}}}{B{F{G{H{I}}}}}}"
> test.tree <- string.to.tree(str1)
> str1
[1] "{A{C{D{E}}}{B{F{G{H{I}}}}}}"
> test.tree$Sort("label")
> tree.to.string(test.tree)
[1] "{A{B{F{G{H{I}}}}}{C{D{E}}}}"
Run Code Online (Sandbox Code Playgroud)

需要注意的是,你想要做的Sort,并tee.to.string在单独的行-在一些极端情况(如单节点"树")Sort()将返回一个NULL

在评论中,您询问了"看到"没有子ID号的树.这可以通过levelName在树的属性上设置格式化功能来实现.基本上,无论何时print树,树都会遍历每个节点并打印levelName属性 - 您可以像任何其他打印属性一样对其进行格式化.

示例格式函数:

strip.num.from.levelName <- function(x){ #If string ends with _something, strip out everything after the last underscore
  x.vec <- strsplit(x,"")[[1]]
  which.sep <- which(x.vec == "_")
  if(length(which.sep)<=0)
    return(x)
  else 
    return(paste(x.vec[1:(tail(which.sep,1)-1)],collapse=""))
}
Run Code Online (Sandbox Code Playgroud)

完成此功能后,将其应用于树SetFormat(test.tree,"levelName",strip.num.from.levelName).这将删除树的所有简单打印输出中的数字

  • @Avi从逻辑的角度来看,即使您使用的只是`string`函数,您也将进行树操作,除非这样代码更容易阅读,更容易修改,并且如果出现问题则更容易修复.例如,您遇到的新示例的错误是因为(我刚刚发现)`data.tree`不喜欢有多个具有非唯一名称的子节点.我通过在树中的所有节点名称附加一个id号并将原始节点名称移动到属性中来修复此问题 - 只需3行额外代码,这要归功于`data.tree中的所有便捷功能. (3认同)
  • @Avi另外,新的示例字符串是否已经排序?唯一有孩子的节点是ASTV(两个孩子都是DP,因此不需要排序)和ALTV(儿童DL和LBE已经按字母顺序排列) (2认同)