JorisChau/rrapply

Method to insert new elements

nvelden opened this issue · 1 comments

I am working on making nested lists for visualisation in a tree map. For this, I was wondering if it would be possible using your package to insert new elements into nested lists by key matching.

To illustrate let's say we have the below nested list

# hierarchy with dataframes
level1 <- data.frame(name = c("gp1", "gp2","gp3"), value = c(30, 40, 30)) # granpa
level11 <- data.frame(name = c("pA", "pB"), value = c(10,20))   # 2nd level parent
level12 <- data.frame(name = c("pD", "pE"), value = c(20,20))
level111 <- data.frame(name = c("c1", "c2"), value = c(3,7))    # 3rd level child
level112 <- data.frame(name = c("c3", "c4"), value = c(10,5))
level1121 <- data.frame(name = c("b1", "b2"), value = c(2,6))   # 4th level baby
level112[1, "children"][[1]] <- list(level1121)
level11[1, "children"][[1]] <- list(level111)
level11[2, "children"][[1]] <- list(level112)
level1[1, "children"][[1]] <- list(level11)
level1[2, "children"][[1]] <- list(level12)

When we convert this to a JSON it will look like this:

library(jsonify)
jsonlite::toJSON(level1, pretty = TRUE, auto_unbox = TRUE)
[
  {
    "name": "gp1",
    "value": 30,
    "children": [
      {
        "name": "pA",
        "value": 10,
        "children": [
          {
            "name": "c1",
            "value": 3
          },
          {
            "name": "c2",
            "value": 7
          }
        ]
      },
      {
        "name": "pB",
        "value": 20,
        "children": [
          {
            "name": "c3",
            "value": 10,
            "children": [
              {
                "name": "b1",
                "value": 2
              },
              {
                "name": "b2",
                "value": 6
              }
            ]
          },
          {
            "name": "c4",
            "value": 5,
            "children": {}
          }
        ]
      }
    ]
  },
  {
    "name": "gp2",
    "value": 40,
    "children": [
      {
        "name": "pD",
        "value": 20
      },
      {
        "name": "pE",
        "value": 20
      }
    ]
  },
  {
    "name": "gp3",
    "value": 30,
    "children": {}
  }
]

And the tree graph will look as follows:

Screenshot 2022-10-28 at 10 27 03

As you can see it gets very confusing to add extra child elements and it would be very helpful if I could use your package to for instance do something like this:

# 5th level baby
level11211 <- data.frame(name = c("d1", "d2"), value = c(5,6))   # 5th level baby

child1 <- rrapply(
    child1,
    condition = \(x, .xname)
                 .xname == "b1", # Insert new children where name == "b1"
    f = \(x) list(children = level11211),             
    how = "insert"
)

Screenshot 2022-10-28 at 10 25 38

@nvelden: it seems this can be done using the (default) option how = "replace",

## insert new children data.frame
level1 <- rrapply(
  level1,
  classes = c("list", "data.frame"),
  condition = \(x) "b1" %in% x$name,
  f = \(x) { x[x$name == "b1", "children"][[1]] <- list(level11211); x }
)

str(level1)
#> 'data.frame':    3 obs. of  3 variables:
#>  $ name    : chr  "gp1" "gp2" "gp3"
#>  $ value   : num  30 40 30
#>  $ children:List of 3
#>   ..$ :'data.frame': 2 obs. of  3 variables:
#>   .. ..$ name    : chr  "pA" "pB"
#>   .. ..$ value   : num  10 20
#>   .. ..$ children:List of 2
#>   .. .. ..$ :'data.frame':   2 obs. of  2 variables:
#>   .. .. .. ..$ name : chr  "c1" "c2"
#>   .. .. .. ..$ value: num  3 7
#>   .. .. ..$ :'data.frame':   2 obs. of  3 variables:
#>   .. .. .. ..$ name    : chr  "c3" "c4"
#>   .. .. .. ..$ value   : num  10 5
#>   .. .. .. ..$ children:List of 2
#>   .. .. .. .. ..$ :'data.frame': 2 obs. of  3 variables:
#>   .. .. .. .. .. ..$ name    : chr  "b1" "b2"
#>   .. .. .. .. .. ..$ value   : num  2 6
#>   .. .. .. .. .. ..$ children:List of 2
#>   .. .. .. .. .. .. ..$ :'data.frame':   2 obs. of  2 variables:
#>   .. .. .. .. .. .. .. ..$ name : chr  "d1" "d2"
#>   .. .. .. .. .. .. .. ..$ value: num  5 6
#>   .. .. .. .. .. .. ..$ : NULL
#>   .. .. .. .. ..$ : NULL
#>   ..$ :'data.frame': 2 obs. of  2 variables:
#>   .. ..$ name : chr  "pD" "pE"
#>   .. ..$ value: num  20 20
#>   ..$ : NULL

If you think a separate option (e.g. how = "insert") is required for this purpose, perhaps you could share an example where the current options how = "replace" and/or how = "list" would be insufficient? Thanks!