根据列表项的嵌套内容删除列表项

Delete list items based on its nested content

提问人:ahnungslos 提问时间:10/16/2023 最后编辑:ahnungslos 更新时间:10/17/2023 访问量:78

问:

这基本上是我之前问题的衍生问题。

考虑到以下示例数据,我想递归删除包含该项目的所有(以及没有更多子项的父项),反之亦然,在保持列表结构的同时复制所有包含该项目的内容(请参阅列表)。childrenselected = FALSEchildrenselected = TRUEexpected_output

到目前为止,我的尝试失败了:

# data --------------------------------------------------------------------
nodes <- list(
  list(
    text = "RootA",
    state = list(loaded = TRUE, opened = TRUE, selected = TRUE, disabled = FALSE),
    children = list(
      list(
        text = "ChildA1",
        state = list(loaded = TRUE, opened = TRUE, selected = TRUE, disabled = FALSE)
      ),
      list(
        text = "ChildA2",
        state = list(loaded = TRUE, opened = TRUE, selected = FALSE, disabled = FALSE)
      )
    )
  ),
  list(
    text = "RootB",
    state = list(loaded = TRUE, opened = TRUE, selected = FALSE, disabled = FALSE),
    children = list(
      list(
        text = "ChildB1",
        state = list(loaded = TRUE, opened = TRUE, selected = FALSE, disabled = FALSE)
      ),
      list(
        text = "ChildB2",
        state = list(loaded = TRUE, opened = TRUE, selected = FALSE, disabled = FALSE)
      )
    )
  )
)

# Error in x[[i]] : subscript out of bounds -------------------------------
delete_unselected_nodes <- function(x) {
  y <- list()
  for (i in seq_along(x)) {
    value <- x[[i]]
    if("state" %in% names(x)){
      if(x[["state"]][["selected"]] == TRUE) {
        y <- c(y, x[[i]]) 
      }
    } else {
      x[[i]] <- delete_unselected_nodes(value)
    }
  }
}

delete_unselected_nodes(nodes)

# expected output ---------------------------------------------------------
expected_output <- list(
  list(
    text = "RootA",
    state = list(loaded = TRUE, opened = TRUE, selected = TRUE, disabled = FALSE),
    children = list(
      list(
        text = "ChildA1",
        state = list(loaded = TRUE, opened = TRUE, selected = TRUE, disabled = FALSE)
      )
    )
  )
)
R jstreer

评论


答:

3赞 dufei 10/17/2023 #1

我会使用 purrr 中的功能来处理列表并定义一些(谓词)函数以保持其整洁:

library(tidyverse)
library(lobstr)

# define sample data ------------------------------------------------------

# ...

# define functions --------------------------------------------------------

# filter list of children to keep only where selected == TRUE
delete_unselected_children <- function(children_list) {
  keep(
    children_list,
    .p = \(x) x$state$selected)
}

# replace list element "children" of root with filtered list of children
delete_from_root <- function(root) {
  modify_in(
    root,
    .where = list("children"),
    .f = delete_unselected_children
  )
}

# define predicate function to drop roots without children
has_no_children <- function(root) {
  is_empty(root$children)
}


# apply -------------------------------------------------------------------

result <- nodes |> 
  map(delete_from_root) |> 
  discard(has_no_children)

lobstr::tree(result)
#> <list>
#> └─<list>
#>   ├─text: "RootA"
#>   ├─state: <list>
#>   │ ├─loaded: TRUE
#>   │ ├─opened: TRUE
#>   │ ├─selected: TRUE
#>   │ └─disabled: FALSE
#>   └─children: <list>
#>     └─<list>
#>       ├─text: "ChildA1"
#>       └─state: <list>
#>         ├─loaded: TRUE
#>         ├─opened: TRUE
#>         ├─selected: TRUE
#>         └─disabled: FALSE

创建于 2023-10-16 with reprex v2.0.2