【问题标题】:Recursively remove 'parent' property based on child's condition根据孩子的情况递归删除“父母”属性
【发布时间】:2021-02-08 10:05:40
【问题描述】:

我有一个如下所示的访问 JSON 对象

{
  "data": [
    {
      "label": "Self Service",
      "data": {
        "roles": [
          "Employee",
          "Manager",
          "System Administrator"
        ]
      },
      "children": [
        {
          "label": "Attendance",
          "icon": "pi pi-file",
          "data": {
            "roles": [
              "Employee",
              "System Administrator"
            ]
          },
          "children": [
            {
              "label": "Clocking",
              "icon": "pi pi-file",
              "data": {
                "roles": [
                  "Employee",
                  "System Administrator"
                ],
                "routerLink": ["ESS-ATT-clocking"]
              }
            },
            {
              "label": "History",
              "icon": "pi pi-file",
              "data": {
                "roles": [
                  "Employee",
                  "System Administrator"
                ]
              }
            }
          ]
        },
        {
          "label": "Claim",
          "icon": "pi pi-file",
          "data": {
            "roles": [
              "Manager",
              "System Administrator"
            ]
          },
          "children": [
            {
              "label": "Entitlement & Request",
              "icon": "pi pi-file",
              "data": {
                "roles": [
                  "Manager",
                  "System Administrator"
                ]
              }
            }
          ]
        }
      ]
    },
  ]
}

存储在变量accessCtrl中。我还有一个变量

role = "Employee"

每个子节点都与“children”属性相连。 如果 data.role 数组中不存在“角色”,我如何循环(递归)删除整个 JSON 对象“accessCtrl”并删除特定节点?

例如

role = "Manager"

对象应该返回

{
  "data": [
    {
      "label": "Self Service",
      "data": {
        "roles": [
          "Employee",
          "Manager",
          "System Administrator"
        ]
      },
      "children": [
        {
          "label": "Claim",
          "icon": "pi pi-file",
          "data": {
            "roles": [
              "Manager",
              "System Administrator"
            ]
          },
          "children": [
            {
              "label": "Entitlement & Request",
              "icon": "pi pi-file",
              "data": {
                "roles": [
                  "Manager",
                  "System Administrator"
                ]
              }
            }
          ]
        }
      ]
    },
  ]
}

这是我当前的代码,它似乎无法正常工作。

function removeNode(obj, parent) {
  for (let prop in obj) {
    if (
      prop === "data" &&
      prop.hasOwnProperty("roles") &&
      !prop.roles.includes(this.role)
    ) {
      if (parent) {
        delete parent.children;
      }
    } else if (typeof obj[prop] === "object") removeNode(obj[prop], obj);
  }
}

removeNode(this.accessCtrl, null);
console.log("this.accessCtrl=", this.accessCtrl);

【问题讨论】:

    标签: javascript json recursion javascript-objects


    【解决方案1】:

    要使函数递归,它需要调用自身。 如果您需要更多关于其工作原理的说明,请告诉我。

    const input = {
      "data": [{
        "label": "Self Service",
        "data": {
          "roles": [
            "Employee",
            "Manager",
            "System Administrator"
          ]
        },
        "children": [{
          "label": "Attendance",
          "icon": "pi pi-file",
          "data": {
            "roles": [
              "Employee",
              "System Administrator"
            ]
          },
          "children": [{
            "label": "Clocking",
            "icon": "pi pi-file",
            "data": {
              "roles": [
                "Employee",
                "System Administrator"
              ],
              "routerLink": ["ESS-ATT-clocking"]
            }
          },
            {
              "label": "History",
              "icon": "pi pi-file",
              "data": {
                "roles": [
                  "Employee",
                  "System Administrator"
                ]
              }
            }
          ]
        },
          {
            "label": "Claim",
            "icon": "pi pi-file",
            "data": {
              "roles": [
                "Manager",
                "System Administrator"
              ]
            },
            "children": [{
              "label": "Entitlement & Request",
              "icon": "pi pi-file",
              "data": {
                "roles": [
                  "Manager",
                  "System Administrator"
                ]
              }
            }]
          }
        ]
      }]
    }
    
    const role = "Manager";
    
    const removeRoles = (tree, role) => {
      const newTree = []
      for (const item of tree) {
        if (item.data.roles.includes(role)) {
          if (item.children) {
            item.children = removeRoles(item.children, role) // this is where it gets recursive
          }
          newTree.push(item)
        }
      }
      return newTree;
    }
    
    const result = { data: removeRoles(input.data, role) }
    
    console.log(result);

    【讨论】:

      【解决方案2】:

      我会将过滤递归数组的代码与测试业务需求的实际代码分开(这里是({data: {roles}}) => roles .includes ('Manager')。)这是一种可能性:

      const filterDeep = (pred) => (xs) =>
        xs .flatMap (x => pred (x)
          ? [{... x, children: filterDeep (pred) (x .children || [])}] 
          : []
        )
      
      const justManagers = (({data, ...rest}) => ({
        ...rest,
        data: filterDeep (({data: {roles}}) => roles .includes ('Manager')) (data)
      }))
      
      const input = {data: [{label: "Self Service", data: {roles: ["Employee", "Manager", "System Administrator"]}, children: [{label: "Attendance", icon: "pi pi-file", data: {roles: ["Employee", "System Administrator"]}, children: [{label: "Clocking", icon: "pi pi-file", data: {roles: ["Employee", "System Administrator"], routerLink: ["ESS-ATT-clocking"]}}, {label: "History", icon: "pi pi-file", data: {roles: ["Employee", "System Administrator"]}}]}, {label: "Claim", icon: "pi pi-file", data: {roles: ["Manager", "System Administrator"]}, children: [{label: "Entitlement & Request", icon: "pi pi-file", data: {roles: ["Manager", "System Administrator"]}}]}]}]}
      
      console .log (
        justManagers (input)
      )
      .as-console-wrapper {max-height: 100% !important; top: 0}

      filterDeep 执行递归树遍历,并且仅包含与我们的谓词匹配的那些节点。 justManager 对输入结构做了一些调整,这样我们就可以只关注data 属性,然后调用filterDeep 将它传递给我们的谓词,以测试我们的节点是否具有“经理”角色。它使我们输入数据的任何其他属性保持不变。

      【讨论】:

      • 我无法判断代码的效率(因为对于中级编码器来说太多了)。 @Scott 你是忍者!但我决定采用第一个解决方案,因为我可能很难维护您的代码。这对我来说太先进了:)
      【解决方案3】:

      这是使用object-scan 的解决方案。我们使用对象扫描进行数据处理,但它确实需要一些时间来绕开你的脑袋。从概念上讲,解决方案很简单:我们检查“叶子优先”,然后处理层次结构并在 (1) 不存在子节点且 (2) 不存在所需角色时删除

      // const objectScan = require('object-scan');
      
      const input = { data: [{ label: 'Self Service', data: { roles: ['Employee', 'Manager', 'System Administrator'] }, children: [{ label: 'Attendance', icon: 'pi pi-file', data: { roles: ['Employee', 'System Administrator'] }, children: [ { label: 'Clocking', icon: 'pi pi-file', data: { roles: ['Employee', 'System Administrator'], routerLink: ['ESS-ATT-clocking'] } }, { label: 'History', icon: 'pi pi-file', data: { roles: ['Employee', 'System Administrator'] } } ] }, { label: 'Claim', icon: 'pi pi-file', data: { roles: ['Manager', 'System Administrator'] }, children: [ { label: 'Entitlement & Request', icon: 'pi pi-file', data: { roles: ['Manager', 'System Administrator'] } } ] }] }] };
      
      const prune = (role, data) => objectScan(['{data,**.children}[*]'], {
        rtn: 'count',
        filterFn: ({ value, property, parent }) => {
          if (
            !value.data.roles.includes(role)
            && (value.children || []).length === 0
          ) {
            parent.splice(property, 1);
            return true;
          }
          return false;
        }
      })(data);
      
      console.log(prune('Manager', input)); // return number of deletions
      // => 3
      console.log(input);
      /* => { data: [
        {
          label: 'Self Service',
          data: { roles: [ 'Employee', 'Manager', 'System Administrator' ] },
          children: [
            { label: 'Claim', icon: 'pi pi-file', data: { roles: [ 'Manager', 'System Administrator' ] }, children: [
              { label: 'Entitlement & Request', icon: 'pi pi-file', data: { roles: [ 'Manager', 'System Administrator' ] } }
            ] }
          ]
        }
      ] } */
      .as-console-wrapper {max-height: 100% !important; top: 0}
      <script src="https://bundle.run/object-scan@13.8.0"></script>

      免责声明:我是object-scan的作者

      【讨论】:

        猜你喜欢
        • 2017-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-29
        • 1970-01-01
        相关资源
        最近更新 更多