如何根据列表项的嵌套内容递归删除列表项

How to recursively delete list items based on its nested content

提问人:ahnungslos 提问时间:11/17/2023 最后编辑:ahnungslos 更新时间:11/18/2023 访问量:40

问:

我正在尝试根据其嵌套内容递归删除列表项(如果删除)。checked = TRUE

我最近在这里问了一个类似的问题。但是,我刚刚意识到给定的答案不能递归工作。

这是我的示例数据:

library(jsTreeR)
library(jsonlite)

nodes <- list(
  list(
    text = "Branch 1",
    state = list(
      opened = TRUE,
      disabled = FALSE,
      selected = FALSE
    ),
    type = "parent",
    children = list(
      list(
        text = "Leaf A",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = FALSE
        ),
        type = "child"
      ),
      list(
        text = "Leaf B",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = FALSE
        ),
        type = "child"
      ),
      list(
        text = "Leaf C",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = TRUE
        ),
        type = "child"
      ),
      list(
        text = "Leaf D",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = FALSE
        ),
        type = "child",
        children = list(
          list(
            text = "Leaf D1",
            state = list(
              opened = TRUE,
              disabled = FALSE,
              selected = FALSE,
              checked = FALSE
            ),
            type = "child"
          ),
          list(
            text = "Leaf D2",
            state = list(
              opened = TRUE,
              disabled = FALSE,
              selected = FALSE,
              checked = TRUE
            ),
            type = "child"
          )
        )
      )
    )
  ),
  list(
    text = "Branch 2",
    type = "parent",
    state = list(
      opened = TRUE,
      disabled = FALSE,
      selected = FALSE,
      checked = FALSE
    )
  )
)


jstree(nodes, checkboxes = TRUE, checkWithText = FALSE)
# toJSON(nodes, pretty = TRUE)

我尝试使用基础 R 和 rrapply,但无法让它正常工作:

delete_unchecked <- function(x) {
  for (i in seq_along(x)) {
    value <- x[[i]]
    if (is.list(value)) {
      x[[i]] <- delete_unchecked(value)
    } else {
      if("state" %in% names(x) && isTRUE(x$state$checked)){x[[i]] <- NULL}
    }
  }
  x
}

library(rrapply)
result <- rrapply(nodes, condition = function(x){
  if("state" %in% names(x)){
    isTRUE(x$state$checked)
  } else {TRUE}
}, how = "prune")

这是我的预期输出:

result

expected_output <- list(
  list(
    text = "Branch 1",
    state = list(
      opened = TRUE,
      disabled = FALSE,
      selected = FALSE
    ),
    type = "parent",
    children = list(
      list(
        text = "Leaf A",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = FALSE
        ),
        type = "child"
      ),
      list(
        text = "Leaf B",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = FALSE
        ),
        type = "child"
      ),
      list(
        text = "Leaf D",
        state = list(
          opened = TRUE,
          disabled = FALSE,
          selected = FALSE,
          checked = FALSE
        ),
        type = "child",
        children = list(
          list(
            text = "Leaf D1",
            state = list(
              opened = TRUE,
              disabled = FALSE,
              selected = FALSE,
              checked = FALSE
            ),
            type = "child"
          )
        )
      )
    )
  ),
  list(
    text = "Branch 2",
    type = "parent",
    state = list(
      opened = TRUE,
      disabled = FALSE,
      selected = FALSE,
      checked = FALSE
    )
  )
)

PS:我更喜欢 R 基础答案 - 但是,对其他建议持开放态度。

R 递归 咕噜 jstreer

评论


答:

1赞 MrFlick 11/18/2023 #1

您可以使用一些递归来检查每个节点及其子节点

remove_checked <- function(x) {
  drop_null <- function(x) Filter(Negate(is.null), x)
  is_checked <- function(x) "state" %in% names(x) && "checked" %in% names(x$state) && x$state$checked
  drop <- function(x) {
    if (is_checked(x)) return(NULL)
    if ("children" %in% names(x)) {
      x$children <- drop_null(lapply(x$children, drop))
    }
    x
  }
  drop_null(lapply(x, drop))
}
result <- remove_checked(nodes)

我们将选中的 NULL 换成 NULL,然后从列表中删除 NULL。