Necesito filtrar una estructura anidada, que se ve así, según la consulta. Necesito devolver todos los objetos, incluido el objeto principal del subárbol, que coinciden con la cadena de consulta en el nombre del objeto. Por favor ayuda, estoy atascado.
[
{
name: 'bob',
type: 1,
children: [
{
name: 'bob',
type: 2,
children: [
{
name: 'mike',
type: 3,
children: [
{
name:'bob',
type: 7,
children: []
},
{
name: 'mike',
type: 9,
children: []
}
]
}
]
},
{
name: 'mike',
type: 2
}
]
}
]
En este momento puedo encontrar una coincidencia en el árbol de forma recursiva, pero la función devuelve el objeto en la primera coincidencia y no busca más profundamente en los subniveles en el mismo objeto. ¿Alguna sugerencia, cómo puedo modificar el código para buscar todos los niveles de forma recursiva?
return tree.map(copy).filter(function filterNested(node) {
if (node.name.toLowerCase().indexOf(query) !== -1) {
return true;
}
if (node.children) {
return (node.children = node.children.map(copy).filter(filterNested))
.length;
}
});
Si estoy buscando la consulta 'bob', el resultado esperado debería ser,
const arr = [
{
name: 'bob',
type: 1,
children: [
{
name: 'bob',
type: 2,
children: [
{
name: 'mike',
type: 3,
children: [
{
name:'bob',
type: 7
},
]
}
]
},
]
}
]
4 respuestas
Podría reducir la matriz y construir nuevos objetos con hijos opcionales, si tienen una longitud que no sea cero.
function filter(array, fn) {
return array.reduce((r, o) => {
var children = filter(o.children || [], fn);
if (fn(o) || children.length) r.push(Object.assign({}, o, children.length && { children }));
return r;
}, []);
}
var data = [{ name: 'bob', type: 1, children: [{ name: 'bob', type: 2, children: [{ name: 'mike', type: 3, children: [{ name: 'bob', type: 7 }, { name: 'same', typ: 9 }] }] }, { name: 'mike', type: 2 }] }],
result = filter(data, ({ name }) => name.toLowerCase() === 'bob');
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Simplemente usaría un buen patrón de visitante antiguo para atravesar y construir un nuevo árbol.
class Visitor {
constructor(predicate) {
this.predicate = predicate;
}
visit(item) {
if (Array.isArray(item)) {
return this.visitArray(item);
} else if (item) {
return this.visitItem(item);
}
}
visitArray(item) {
const result = [];
for (let e of item) {
const item = this.visit(e);
if (item) {
result.push(item);
}
}
return result;
}
visitItem(item) {
const children = this.visit(item.children);
const hasChildren = (children && children.length > 0);
if (hasChildren || this.predicate(item)) {
return {
name: item.name,
type: item.type,
children: children
}
}
return null;
}
}
const visitor = new Visitor((item) => item.name === "bob");
const result = visitor.visit(data);
console.log(result);
Puede usar una reducción recursiva para esto, donde verifica si hay hijos o si el nombre coincide antes de acumular el objeto:
const example = [{
name: 'bob',
type: 1,
children: [{
name: 'bob',
type: 2,
children: [{
name: 'mike',
type: 3,
children: [{
name: 'bob',
type: 7,
children: []
},
{
name: 'mike',
type: 9,
children: []
}
]
}]
},
{
name: 'mike',
type: 2
}
]
}];
function reduceName(accum, item, matcher) {
item.children = (item.children || []).reduce((a,i)=>reduceName(a,i,matcher),[]);
if (!item.children.length) delete item.children;
if (matcher(item) || item.children) accum.push(item);
return accum;
}
console.log(example.reduce((a,i)=>reduceName(a,i,x=>x.name==='bob'),[]));
¿Algo así, tal vez?
function nestedFilter(query, nodes) {
return nodes.reduce((result, node) => {
const filteredChildren = node.children && nestedFilter(query, node.children);
const nameMatches = node.name.toLowerCase().indexOf(query) !== -1;
const childrenMatch = filteredChildren && filteredChildren.length;
const shouldKeep = nameMatches || childrenMatch;
return shouldKeep
? result.concat({ ...node, children: filteredChildren })
: result;
}, []);
}
Preguntas relacionadas
Nuevas preguntas
javascript
Para preguntas sobre la programación en ECMAScript (JavaScript / JS) y sus diversos dialectos / implementaciones (excepto ActionScript). Incluya todas las etiquetas relevantes en su pregunta; por ejemplo, [node.js], [jquery], [json], etc.