Удалить объект из вложенного дерева, если он не соответствует ни одному из выбранных идентификаторов

У меня есть выбранный массив

this.selectedArray = ["1:Tree", "2:PT", "5:PT - DD", "11:PT - C", "3:SAC", "7:SAC - DR", "6:SAC - DDE"]

и древовидная структура с детьми:

this.root =    
{"children": [
   {"children": [
     {
      "children": [],
      "id": 12,
      "name": "PT - D"
    },
    {
      "children": [
        {
          "children": [],
          "id": 8,
          "name": "PT-33"
        },
        {
          "children": [],
          "id": 10,
          "name": "PT-62"
        },
        {
          "children": [],
          "id": 9,
          "name": "PT-52"
        }
      ],
      "id": 4,
      "name": "PT - 32"
    },
    {
      "children": [
        {
          "children": [],
          "id": 11,
          "name": "PT - C"
        }
      ],
      "id": 5,
      "name": "PT - DD"
    }
  ],
  "id": 2,
  "name": "PT"
},
{
  "children": [
    {
      "children": [],
      "id": 7,
      "name": "SAC - DR"
    },
    {
      "children": [],
      "id": 6,
      "name": "SAC - DE"
    }
  ],
  "id": 3,
  "name": "SAC"
}
],
 "id": 1,
 "name": "Tree"
}

Я хотел бы удалить узел из дерева, если node.Id + ':' + node.name не соответствует ни одному из элементов в this.selectedArray.

У меня возникают проблемы с поиском алгоритма, который позволит мне удалить все данные объекта, которые не соответствуют ни одному из элементов в этом., Выбранном из глубоко вложенного дерева.

Вот код:

 setSearchResult(selectedArray) {
    if (!!selected) {
        let this.tree = JSON.parse(JSON.stringify(this.root));
        this.topLevelGroups = this.removeFromTree(this.tree, selectedArray, null, null);
    }
}

removeFromTree(parent, selectedArray, grandParent, idx) {
    let { name, id, children } = parent;
    let parentId = id + ':' + name;
    if (!!selectedArray) {
        if (!selectedArray.includes(parentId)) {
            if (grandParent) {
                grandParent.children.splice(idx, 1);
            } 
            else return null;
        }
        if (!!parent && !!children) {
            for (let i = 0; i < children.length; i++) {
                this.removeFromTree(children[i], selectedArray, parent, i);
            }
        }
    }
    return this.tree.children;
  }

Я думаю, что проблема в том, что после выполнения кода, который имеет this.slice, он вернется и не перейдет к своему брату. Есть предложения по этому поводу?

Всего 2 ответа


Вы можете использовать немутирующий подход и уменьшить массив, уважая детей.

Это решение использует хеш-таблицу для требуемого id качестве ключа и name качестве значения из разделенных значений selected массива.

В результате включаются только известные узлы.

const
    filter = (r, { children = [], ...o }) => {
        if (nodes[o.id] !== o.name) return r;
        children = children.reduce(filter, []);
        r.push(children.length ? { ...o, children } : o);
        return r;
    },
    selected = ["1:Tree", "2:PT", "5:PT - DD", "11:PT - C", "3:SAC", "7:SAC - DR", "6:SAC - DDE"],
    nodes = selected.reduce((r, s) => {
        var [k, v] = s.split(':');
        r[k] = v;
        return r;
    }, {}),
    tree = { children: [{ children: [{ children: [], id: 12, name: "PT - D" }, { children: [{ children: [], id: 8, name: "PT-33" }, { children: [], id: 10, name: "PT-62" }, { children: [], id: 9, name: "PT-52" }], id: 4, name: "PT - 32" }, { children: [{ children: [], id: 11, name: "PT - C" }], id: 5, name: "PT - DD" }], id: 2, name: "PT" }, { children: [{ children: [], id: 7, name: "SAC - DR" }, { children: [], id: 6, name: "SAC - DE" }], id: 3, name: "SAC" }], id: 1, name: "Tree" },
    result = tree.children = tree.children.reduce(filter, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }


Простая рекурсивная функция фильтра, потому что вы используете строки в selectedArray вы можете легко использовать Set для проверки узла.

const tags = new Set(selectedArray);

function filterArray ({ children, id, name }) {
    const tag = `${id}:${name}`;
    if (tags.has(tag)) {
        return {
            id,
            name,
            children: children.map(filterArray).filter((child) => child !== null)
        };
    }
    return null;
}


const output = filterArray(root);
console.log(JSON.stringify(output, null, 4));

Есть идеи?

10000