【问题标题】:conditionnally extract values from a nested array in javascript有条件地从javascript中的嵌套数组中提取值
【发布时间】:2021-05-01 05:14:40
【问题描述】:

如何从嵌套数组中提取值列表?符合条件?

const tree = {
   "menu_id":"root",
   "open":true,
   "items":[
      {
        "menu_id":"Brussels",
        "open":false,
         "items":[
            {
               "menu_id":"Brussels/CBD",
               "open":true,
               "items":[
                  {
                     "menu_id":"Brussels/CBD/Centre",
                     "open":false
                  },
                  {
                     "menu_id":"Brussels/CBD/Louise",
                     "open":true
                  },
                  {
                     "menu_id":"Brussels/CBD/Léopold",
                     "open":false
                  },
                  {
                     "menu_id":"Brussels/CBD/Midi",
                     "open":true
                  },
                  {
                     "menu_id":"Brussels/CBD/North",
                     "open":false
                  }
               ]
            }
        ]
      }
    ]
}

我想获取一个 menu_id 值列表,其中 open 属性为 false,因此会给出:

var closed = ['Brussels','Brussels/CBD/Centre','Brussels/CBD/Léopold','Brussels/CBD/North']

我该怎么做?

谢谢!

【问题讨论】:

  • 请访问help center,使用tour查看内容和How to Ask。做一些研究,搜索关于 SO 的相关主题;如果您遇到困难,请发布您的尝试minimal reproducible example,并使用[<>] sn-p 编辑器记录输入和预期输出。
  • 所以忽略"menu_id":"root", "open":true,
  • @mplungjan:虽然这个问题可能没有表现出足够的努力,但您建议的副本却完全不同。这个人正在寻找一种将所有匹配节点收集到一个数组中的方法,而不管深度如何。那个保持树结构完整,只保留匹配的叶节点。

标签: javascript recursion multidimensional-array nested


【解决方案1】:

编写此代码的一种有用方法是构建一个通用函数来处理各种树和任意谓词,然后在其上构建您的函数。

此版本执行此操作,然后部分应用描述树结构的函数以获取新函数,部分应用谓词以获取另一个函数,该函数接受树并返回与谓词匹配的所有节点。最后,我们的 main 函数接受一棵树,调用前面的函数并从每个结果中提取 id 节点。

const filterDeep = (getKids) => (pred) => (tree) => [
  ... (pred (tree) ? [tree] : []),
  ... (getKids (tree)) .flatMap (filterDeep (getKids) (pred))
]

const filterItems = 
  filterDeep (({items = []}) => items)

const closed =
  filterItems (({open}) => !open)

const closedIds = (tree) =>
  closed (tree) .map (({menu_id}) => menu_id)

const tree = {menu_id: "root", open: true, items: [{menu_id: "Brussels", open: false, items: [{menu_id: "Brussels/CBD", open: true, items: [{menu_id: "Brussels/CBD/Centre", open: false}, {menu_id: "Brussels/CBD/Louise", open: true}, {menu_id: "Brussels/CBD/Léopold", open: false}, {menu_id: "Brussels/CBD/Midi", open: true}, {menu_id: "Brussels/CBD/North", open: false}]}]}]}

console .log (closedIds (tree))

我们显然可以在filterDeep 上直接写closedIds,如下所示:

const closedIds = (tree) =>
  filterDeep (({items}) => items) (({open}) => open == false) (tree) 
    .map (({menu_id}) => menu_id)

而且,虽然这并没有什么问题,但这些中间函数可能是可重用的,我认为这有助于使问题更加清晰。例如,filterItems 是一个函数,它接受一个谓词和一个树,其中一个节点的子节点位于一个名为 items 的数组中,并返回与谓词匹配的所有节点(无论嵌套级别如何)。看起来很有用。


但是,如果您只想要一个专用功能,我们可以将所有这些合并成一个相当简单的东西:

const closedIds = (tree) => [
  ... (tree.open ? [] : [tree.menu_id]),
  ... (tree.items || []) .flatMap (closedIds)
]

const tree = {menu_id: "root", open: true, items: [{menu_id: "Brussels", open: false, items: [{menu_id: "Brussels/CBD", open: true, items: [{menu_id: "Brussels/CBD/Centre", open: false}, {menu_id: "Brussels/CBD/Louise", open: true}, {menu_id: "Brussels/CBD/Léopold", open: false}, {menu_id: "Brussels/CBD/Midi", open: true}, {menu_id: "Brussels/CBD/North", open: false}]}]}]}

console .log (closedIds (tree))

【讨论】:

  • filterDeep 的另一个用例:D
  • @Thankyou:我仍然不确定这个名字。我使用了两种不同风格的深度过滤。一个创建一个匹配数组;另一个保持树结构但减少了节点的数量。两者似乎都不比另一个更值得获得 filterDeep 的名字,但是调用一个 deepFilter 和另一个 filterDeep 太令人困惑了。
  • 为了修剪树木但保持形状,我使用了名称 pruneshake
  • @Thankyou:prune 听起来不错。我会为此保留deepFilter
  • 我应该澄清一下,prune 返回没有“过滤”位的树,而 shake 返回“过滤”位。 deepFilter 没有错^^
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
相关资源
最近更新 更多