简体   繁体   English

过滤嵌套数组并与父对象一起更新数组 - JS

[英]Filter nested array and update the array along with the parent object - JS

I have an array of objects and I need to add a key to the object as well as the parent array/object with the same values.我有一个对象数组,我需要为该对象以及具有相同值的父数组/对象添加一个键。

Below is my implementation:下面是我的实现:

 const data = [{ "label": "Grand Parent 1", "index": 0, "code": "GRAND_PARENT_1", "defaultCollapsed": true, "items": [{ "id": 1, "items": [{ "id": 100, "label": "Child 1", "url": "#CHILD_1", "code": "CHILD_1" }, { "id": 200, "label": "Child 2", "url": "#CHILD_2", "code": "CHILD_2" }, { "id": 300, "label": "Child 3", "url": "#CHILD_3", "code": "CHILD_3" }, { "id": 400, "label": "Child 4", "url": "#CHILD_4", "code": "CHILD_4" } ], "defaultCollapsed": false, "label": "Parent 1" }, { "id": 2, "items": [], "defaultCollapsed": true, "label": "Parent 2" }, { "id": 3, "items": [], "defaultCollapsed": true, "label": "Parent 3" }, { "id": 4, "items": [], "defaultCollapsed": true, "label": "Parent 4" } ] }, { "label": "Grand Parent 2", "index": 1, "code": "GRAND_PARENT_2", "defaultCollapsed": true, "items": [] }, { "label": "Grand Parent 3", "index": 2, "code": "GRAND_PARENT_3", "defaultCollapsed": true, "items": [] } ] const filterData = (data, value) => { const r = _.filter(data, item => { const dataMap = _.map(item.items, subItem => { const subItemMap = _.map(subItem.items, subsecItem => { if(subsecItem.code === value) { return item } }) }) }) return r; } console.log(filterData(data, 'CHILD_1'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

So I want to add a key called selected: true to the child as well as the parent objects when the value to the function is CHILD_1;因此,当函数的值为 CHILD_1 时,我想向子对象和父对象添加一个名为selected: true的键;

Expected Output:预期输出:

[
  {
    "label": "Grand Parent 1",
    "index": 0,
    "code": "GRAND_PARENT_1",
    "defaultCollapsed": true,
    "selected": true,
    "items": [
      {
        "id": 1,
        "items": [
          {
            "id": 100,
            "label": "Child 1",
            "url": "#CHILD_1",
            "code": "CHILD_1",
            "selected": true
          },
          {
            "id": 200,
            "label": "Child 2",
            "url": "#CHILD_2",
            "code": "CHILD_2"
          },
          {
            "id": 300,
            "label": "Child 3",
            "url": "#CHILD_3",
            "code": "CHILD_3"
          },
          {
            "id": 400,
            "label": "Child 4",
            "url": "#CHILD_4",
            "code": "CHILD_4"
          }
        ],
        "defaultCollapsed": false,
        "label": "Parent 1",
        "selected": true
      },
      {
        "id": 2,
        "items": [],
        "defaultCollapsed": true,
        "label": "Parent 2"
      },
      {
        "id": 3,
        "items": [],
        "defaultCollapsed": true,
        "label": "Parent 3"
      },
      {
        "id": 4,
        "items": [],
        "defaultCollapsed": true,
        "label": "Parent 4"
      }
    ]
  },
  {
    "label": "Grand Parent 2",
    "index": 1,
    "code": "GRAND_PARENT_2",
    "defaultCollapsed": true,
    "items": []
  },
  {
    "label": "Grand Parent 3",
    "index": 2,
    "code": "GRAND_PARENT_3",
    "defaultCollapsed": true,
    "items": []
  }
]

Please advice.请指教。 I was stuck at trying to filter the data based on the value.我一直试图根据值过滤数据。

You could take a function which returns true or false depending on the find of the wanted key/value for updating the object with another property.您可以使用一个返回truefalse的函数,具体取决于找到所需的键/值以使用另一个属性更新对象。

This approach works for arbitrary depth of data.这种方法适用于任意深度的数据。

 function update(array, key, value, object) { var found = false; array.forEach(o => { if (o[key] === value || update(o.items || [], key, value, object)) { found = true; Object.assign(o, object); } }); return found; } var data = [{ label: "Grand Parent 1", index: 0, code: "GRAND_PARENT_1", defaultCollapsed: true, items: [{ id: 1, items: [{ id: 100, label: "Child 1", url: "#CHILD_1", code: "CHILD_1" }, { id: 200, label: "Child 2", url: "#CHILD_2", code: "CHILD_2" }, { id: 300, label: "Child 3", url: "#CHILD_3", code: "CHILD_3" }, { id: 400, label: "Child 4", url: "#CHILD_4", code: "CHILD_4" }], defaultCollapsed: false, label: "Parent 1" }, { id: 2, items: [], defaultCollapsed: true, label: "Parent 2" }, { id: 3, items: [], defaultCollapsed: true, label: "Parent 3" }, { id: 4, items: [], defaultCollapsed: true, label: "Parent 4" }] }, { label: "Grand Parent 2", index: 1, code: "GRAND_PARENT_2", defaultCollapsed: true, items: [] }, { label: "Grand Parent 3", index: 2, code: "GRAND_PARENT_3", defaultCollapsed: true, items: [] }]; update(data, 'code', 'CHILD_1', { selected: true }); console.log(data);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

If you like to set all not found items to false , you could take an depth first approach and visit all elements.如果您想将所有未找到的项目设置为false ,您可以采用深度优先的方法并访问所有元素。

 function update(array, value) { var found = false; array.forEach(o => { o.selected = update(o.items || [], value) || o.code === value; found = found || o.selected; }); return found; } var data = [{ label: "Grand Parent 1", index: 0, code: "GRAND_PARENT_1", defaultCollapsed: true, items: [{ id: 1, items: [{ id: 100, label: "Child 1", url: "#CHILD_1", code: "CHILD_1" }, { id: 200, label: "Child 2", url: "#CHILD_2", code: "CHILD_2" }, { id: 300, label: "Child 3", url: "#CHILD_3", code: "CHILD_3" }, { id: 400, label: "Child 4", url: "#CHILD_4", code: "CHILD_4" }], defaultCollapsed: false, label: "Parent 1" }, { id: 2, items: [], defaultCollapsed: true, label: "Parent 2" }, { id: 3, items: [], defaultCollapsed: true, label: "Parent 3" }, { id: 4, items: [], defaultCollapsed: true, label: "Parent 4" }] }, { label: "Grand Parent 2", index: 1, code: "GRAND_PARENT_2", defaultCollapsed: true, items: [] }, { label: "Grand Parent 3", index: 2, code: "GRAND_PARENT_3", defaultCollapsed: true, items: [] }]; update(data, 'CHILD_1'); console.log(data);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

This solution is a bit more efficient because it stops as soon as the given child is found.此解决方案效率更高,因为一旦找到给定的孩子,它就会停止。 forEach() doesn't allow you to do that. forEach()不允许你这样做。 I also find it a bit more clear to read.我也觉得读起来更清楚一些。

 function select(items, value) { if (!Array.isArray(items)) { return false; } for (const item of items) { if (item.code === value || select(item.items, key, value)) { item.selected = true; return true; } } return false; } select(data, "CHILD_1");

select() will return true if the child was found and false otherwise. select()将在找到孩子时返回真,否则返回假。

In case you need to unselect something that was previously selected:如果您需要取消选择之前选择的内容:

 function reset(items) { if (!Array.isArray(items)) { return; } for (const item of items) { if (item.selected) { reset(item.items); delete item.selected; break; } } } reset(data);

This approach is as smart as the selection, since it stops as soon as it finds the selected element.这种方法与选择一样聪明,因为它一旦找到所选元素就会停止。

To execute both:要同时执行:

function resetAndSelect(data, value) {
  reset(data);
  select(data, value);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM