Рекурсивная функция и Карта для доступа к элементам в вложенном массиве

91
9

ситуация

    У меня есть вложенный массив, и у меня есть идентификатор для поиска. Как "A_02_02_01_03" Каждый элемент в массиве имеет элемент с именем "children", то есть массив Мой метод довольно длинный, когда я ищу на 4-м слое.

Пример массива

var tree= [
{
"name": "i2",
"children": [
{
"name": "d1",
"children": [],
"id": "DW_02_01",
"beschreibung": "",
"table": []
},
{
"name": "d2",
"children": [
{
"name": "e1",
"children": [
{
"name": "a1",
"children": [],
"id": "A_02_02_01_01",
"beschreibung": "",
"table": []
},
{
"name": "a2",
"children": [],
"id": "A_02_02_01_02",
"beschreibung": "",
"table": []
},
{
"name": "a3",
"children": [],
"id": "A_02_02_01_03",
"beschreibung": "",
"table": []
}'enter code here'
],
"id": "E_02_02_01",
"beschreibung": "",
"table": []
},
{
"name": "e2",
"children": [],
"id": "E_02_02_02",
"beschreibung": "",
"table": []
}
],
"id": "DW_02_02",
"beschreibung": "",
"table": []
},
{
"name": "d3",
"children": [],
"id": "DW_02_03",
"beschreibung": "",
"table": []
}
],
"id": "IW_02",
"beschreibung": "",
"table": []
},
{
"name": "i3",
"children": [],
"id": "IW_03",
"beschreibung": "",
"table": []
}
]

Построение идентификаторов

var daIW = "IW_02";
var daDW = "DW_02_02;
var daE = "E_02_02_01;
var daA = "A_02_02_01_03";

Получение всех моих показателей

var iw_index = tree.findIndex(element => element.id == daIW);
var dw_index = tree[iw_index]["children"].findIndex(element => element.id == daDW);
var e_index = tree[iw_index]["children"][dw_index]["children"].findIndex(element => element.id == daE);
var a_index = tree[iw_index]["children"][dw_index]["children"][e_index]["children"].findIndex(element => element.id == daA);

Доступ к моему элементу

var elementName = tree[iw_index]["children"][dw_index]["children"][e_index]["children"][a_index].name;

Вопрос

Есть ли более короткий способ доступа к самому глубокому элементу "A_02_02_01_03", а затем поиск по каждому индексу?

спросил(а) 2018-02-07T19:04:00+03:00 2 года, 8 месяцев назад
1
Решение
71

Вы можете захотеть, чтобы рекурсия сначала искала дерево:

function search(array = [], id){
for(const node of array){
if(node.id === id) return node;

const sub = search(node.children, id);
if(sub) return sub;
}
}

Таким образом, вы можете:

const result = search(tree, "A_02_02_01_03");

Если вы хотите найти несколько элементов, возможно, лучше создать хэш-таблицу, в которой хранятся все пары id/node, поэтому поиск выполняется очень быстро:

function createLookup(array, hash = new Map){
for(const node of array){
hash.set(node.id, node);
createLookup(node.children, hash);
}
return hash;
}

Таким образом, вы можете:

const hash = createLookup(tree);
const result = hash.get("A_02_02_01_03");

ответил(а) 2018-02-07T19:12:00+03:00 2 года, 8 месяцев назад
58

Я предполагаю, что по какой-то причине вы не можете просто искать запись с id == "A_02_02_01_03". Например, по каким-то причинам вам нужны другие идентификаторы.

Теперь, когда вы подтвердили, что идентификаторы листового узла уникальны, Jonas w отвечает, который использует только идентификатор листового узла (например, "A_02_02_01_03"). Если у вас есть другие идентификаторы, которые могут ускорить процесс, избегая посещения узлов, которые вам не нужно посещать, но для этого вам нужно иметь очень большое дерево.

Если это имеет значение, этот ответ по-прежнему применяется:

Я бы использовал рекурсивную функцию:

function find(node, ids, index = 0) {
const id = ids[index];
const entry = node.find(e => e.id == id);
if (!entry) {
return null;
}
++index;
return index < ids.length ? find(entry.children, ids, index) : entry;
}

и затем назовите его следующим образом:

const result = find(tree, [daIW, daDW, daE, daA]);

Это предполагает, что вы хотите, чтобы запись была результатом.

Живой пример:

var tree= [
{
"name": "i2",
"children": [
{
"name": "d1",
"children": [],
"id": "DW_02_01",
"beschreibung": "",
"table": []
},
{
"name": "d2",
"children": [
{
"name": "e1",
"children": [
{
"name": "a1",
"children": [],
"id": "A_02_02_01_01",
"beschreibung": "",
"table": []
},
{
"name": "a2",
"children": [],
"id": "A_02_02_01_02",
"beschreibung": "",
"table": []
},
{
"name": "a3",
"children": [],
"id": "A_02_02_01_03",
"beschreibung": "",
"table": []
}
],
"id": "E_02_02_01",
"beschreibung": "",
"table": []
},
{
"name": "e2",
"children": [],
"id": "E_02_02_02",
"beschreibung": "",
"table": []
}
],
"id": "DW_02_02",
"beschreibung": "",
"table": []
},
{
"name": "d3",
"children": [],
"id": "DW_02_03",
"beschreibung": "",
"table": []
}
],
"id": "IW_02",
"beschreibung": "",
"table": []
},
{
"name": "i3",
"children": [],
"id": "IW_03",
"beschreibung": "",
"table": []
}
];

var daIW = "IW_02";
var daDW = "DW_02_02";
var daE = "E_02_02_01";
var daA = "A_02_02_01_03";

function find(node, ids, index = 0) {
const id = ids[index];
const entry = node.find(e => e.id == id);
if (!entry) {
return null;
}
++index;
return index < ids.length ? find(entry.children, ids, index) : entry;
}

console.log(find(tree, [daIW, daDW, daE, daA]));

ответил(а) 2018-02-07T19:14:00+03:00 2 года, 8 месяцев назад
41

Попробуйте следующую рекурсивную функцию

//Функция

  function getelement(vtree, id) {
vtree.forEach(function(treeitem) {
if(treeitem["id"] === id) {
console.log(treeitem);
}
else if(treeitem["children"].length){
getelement(treeitem["children"], id);
}
});
};

//Caller

getelement(tree,"A_02_02_01_03");

ответил(а) 2018-02-07T19:52:00+03:00 2 года, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема