Как вывести вложенные списки обходом в ширину?
Есть 2 множества: объекты и связи. Связей для каждой пары объектов по две в обе стороны и есть кольца:
let objects = [
{id: 1, title: "obj1"},
{id: 2, title: "obj2"},
{id: 3, title: "obj3"},
];
let relations = [
{id1: 1, id2: 2, title:"1-2"},
{id1: 2, id2: 1, title:"2-1"},
{id1: 2, id2: 3, title:"2-3"},
{id1: 3, id2: 2, title:"3-2"},
{id1: 1, id2: 3, title:"1-3"},
{id1: 3, id2: 1, title:"3-1"},
];
Надо построить дерево вложенных списков от любого из объектов. Рекурсией (обходом в глубину) это делается очень просто:
function makeTree(id, visited) {
let result = "";
let obj = objects.find(z=>z.id==id);
if (visited.indexOf(id)==-1) {
visited.push(id);
result += `<li><b>${obj.title}</b><ul>`;
for (let rel of relations.filter(z=>z.id1 == id)) {
result += makeTree(rel.id2, visited);
}
result += "</ul></li>";
} else {
result += `<li><i>${obj.title}</i></li>`; //повторы
}
return result;
}
document.getElementById("tree").innerHTML = makeTree(1, []);
результатом этого кода будет:
<ul id="tree">
<li><b>obj1</b>
<ul>
<li>
<b>obj2</b>
<ul>
<li><i>obj1</i></li>
<li>
<b>obj3</b>
<ul>
<li><i>obj2</i></li>
<li><i>obj1</i></li>
</ul>
</li>
</ul>
</li>
<li><i>obj3</i></li>
</ul>
</li>
</ul>
Но мне надо сделать то же самое обходом в ширину, чтобы связи, которые ближе к корню раскрывались быстрее. Т.е. чтобы obj3 развернулся сразу внутри obj1 а не внутри obj2. Не знаю, как объяснить понятнее, чтобы результат стал такой:
<ul id="tree2">
<li>
<b>obj1</b>
<ul>
<li><b>obj2</b>
<ul>
<li><i>obj3</i></li>
</ul>
</li>
<li><b>obj3</b>
<ul>
<li><i>obj2</i></li>
</ul>
</li>
</ul>
</li>
</ul>
Как в принципе работает поиск в ширину с очередью я понимаю:
function makeTree2(id) {
let result = "";
let q = [], visited=[];
q.push(id);
while (q.lenght>0) {
let objid = q.shift();
visited.push(objid);
let obj = objects.find((z) => z.id == id);
//result += ?
for (let rel of relations.filter((z) => z.id1 == objid)) {
if (visited.indexOf(rel.id2) == -1) {
q.push(rel.obj2);
}
}
}
return result;
}
Но как из него выплюнуть вложенный html — нет.
Полный код на CodePen