1

I am working with a list of lists, collected from an XML chunk, that I would like to represent with object defined by the data.tree package for R. The example below seems to work, and I can extract elements from the data.tree representation of the list of lists. However, I cannot figure out how to use any of the text-formatting or visualization options (e.g. igraph) due to the fact that "child" elements of each list are not uniquely labeled.

Ideally, I would like to recursively re-name "Children" with a serial number. For example, convert this:

    Children
    |-- RuleRule
    |-- RuleRule
    |-- RuleRule

To this:

    Children
    |-- RuleRule_01
    |-- RuleRule_02
    |-- RuleRule_03

Or even better, re-name the "Children" according to an attribute such as

Children

    |-- RuleRule_15976
    |-- RuleRule_49444
    |-- RuleRule_15748

Here is a similar question that is almost what I am looking for. I am not sure if the use of data.tree functionality would simplify the re-naming of children elements, or if this should be done before initializing the data.tree object. The tree-traversal capabilities of data.tree seem like the right route, especially since the types of data I will be using can have multiple set of children, at any level.

A self-contained example:

library(data.tree)

# a typical list
l <- structure(list(RuleStart = structure(list(Children = structure(list(
RuleOperator = structure(list(Children = structure(list(RuleRule = structure(list(
    Children = NULL, RefId = "49446"), .Names = c("Children", 
"RefId")), RuleRule = structure(list(Children = NULL, RefId = "15976"), .Names = c("Children", 
"RefId")), RuleRule = structure(list(Children = NULL, RefId = "49444"), .Names = c("Children", 
"RefId")), RuleRule = structure(list(Children = NULL, RefId = "15748"), .Names = c("Children", 
"RefId")), RuleRule = structure(list(Children = NULL, RefId = "49440"), .Names = c("Children", 
"RefId")), RuleRule = structure(list(Children = NULL, RefId = "15746"), .Names = c("Children", 
"RefId")), RuleRule = structure(list(Children = NULL, RefId = "49449"), .Names = c("Children", 
"RefId"))), .Names = c("RuleRule", "RuleRule", "RuleRule", 
"RuleRule", "RuleRule", "RuleRule", "RuleRule")), Type = "product"), .Names = c("Children", 
"Type"))), .Names = "RuleOperator")), .Names = "Children")), .Names = "RuleStart")

# convert XML list into data.tree object
n <- FromListExplicit(l$RuleStart, nameName=NULL, childrenName='Children')

# check
print(n, 'RefId')
Community
  • 1
  • 1
Dylan
  • 61
  • 1
  • 5
  • data.tree requires the name element to be unique at least among siblings. Thus, you have two choices: either make it unique before converting to a data.tree structure (i.e. not use RuleRule as name), or use something else for the name, using the nameName argument. – Christoph Glur Feb 09 '16 at 06:56

1 Answers1

1

Thanks to the author of data.tree for the suggestion. The following function will recursively re-name elements of a list. It seems to work, but comments or a better solution are welcome.

makeNamesUnique <- function(l) {
  l.names <- names(l$Children)
  # multiple children types
  tab <- table(l.names)
  t.names <- names(tab)

  # iterate over types
  for(this.type in seq_along(t.names)) {
    # iterate over duplicate names
    # get an index to this type
    idx <- which(l.names == t.names[this.type])
    for(this.element in seq_along(idx)) {
      # make a copy of this chunk of the tree
      l.sub <- l$Children[[idx[this.element]]]
      # if this is a terminal leaf then re-name and continue
      if(is.null(l.sub$Children)) {
        # print('leaf')
        names(l$Children)[idx[this.element]] <- paste0(t.names[this.type], '_', this.element)
      }
      # otherwise re-name and then step into this element and apply this function recursively
      else {
        # print('branch')
        names(l$Children)[idx[this.element]] <- paste0(t.names[this.type], '_', this.element)
        # fix this branch and splice back into tree
        l$Children[[idx[this.element]]] <- makeNamesUnique(l.sub)
      }
    }
  }

  return(l)
}
Dylan
  • 61
  • 1
  • 5