Większy problem, który próbuję rozwiązać, biorąc pod uwagę te dane:
var data = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4, children: [
{ id: 6 },
{ id: 7, children: [
{id: 8 },
{id: 9 }
]}
]},
{ id: 5 }
]
Chcę zrobić funkcję findById(data, id)
to się zwraca { id: id }
. Na przykład, findById(data, 8)
powinien powrócić { id: 8 }
, i findById(data, 4)
powinien powrócić { id: 4, children: [...] }
.
W tym celu wykorzystałem Array.prototype.find
rekurencyjnie, ale wpadł w kłopoty, gdy return
ciągle zaciera obiekty. Moja implementacja zwraca ścieżka do konkretnego obiektu.
Na przykład kiedy użyłem findById(data, 8)
, zwraca ścieżka do { id: 8 }
:
{ id: 4, children: [ { id: 6 }, { id: 7, children: [ { id: 8}, { id: 9] } ] }
Zamiast tego chciałbym, żeby po prostu wrócił
{ id: 8 }
Implementacja (Node.js v4.0.0)
var data = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4, children: [
{ id: 6 },
{ id: 7, children: [
{id: 8 },
{id: 9 }
]}
]},
{ id: 5 }
]
function findById(arr, id) {
return arr.find(a => {
if (a.children && a.children.length > 0) {
return a.id === id ? true : findById(a.children, id)
} else {
return a.id === id
}
})
return a
}
console.log(findById(data, 8)) // Should return { id: 8 }
// Instead it returns the "path" block: (to reach 8, you go 4->7->8)
//
// { id: 4,
// children: [ { id: 6 }, { id: 7, children: [ {id: 8}, {id: 9] } ] }
Odpowiedzi:
1 dla odpowiedzi № 1Po prostu użyłbym zwykłej pętli i rekurencyjnego wyszukiwania stylu:
function findById(data, id) {
for(var i = 0; i < data.length; i++) {
if (data[i].id === id) {
return data[i];
} else if (data[i].children && data[i].children.length && typeof data[i].children === "object") {
findById(data[i].children, id);
}
}
}
//findById(data, 4) => Object {id: 4, children: Array[2]}
//findById(data, 8) => Object {id: 8}
8 dla odpowiedzi № 2
Problem, jaki masz, to bulgotanie znaleziska. Jeśli identyfikator zostanie znaleziony w zagnieżdżonej strukturze, wywołanie zwrotne próbuje zwrócić element, który jest interpretowany jako true, wartość dla znalezienia.
The
find
Metoda wykonuje funkcję wywołania zwrotnego jeden raz dla każdego elementu obecnego w tablicy, dopóki nie znajdzie takiego, w którym wywołanie zwrotne zwraca prawdziwą wartość. [MDN]
Zamiast znaleźć, sugerowałbym użycie stylu rekurencyjnego do wyszukiwania z krótkim zwarciem, jeśli zostanie znaleziony.
var data = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4, children: [{ id: 6 }, { id: 7, children: [{ id: 8 }, { id: 9 }] }] }, { id: 5 }];
function findById(data, id) {
function iter(a) {
if (a.id === id) {
result = a;
return true;
}
return Array.isArray(a.children) && a.children.some(iter);
}
var result;
data.some(iter);
return result
}
console.log(findById(data, 8));