Saltar al contenido

Filtrar recursivamente array de objetos

Esta reseña fue aprobado por especialistas para asegurar la exactitud de nuestro post.

Solución:

Utilizando .filter() y hacer una llamada recursiva como describí en el comentario anterior es básicamente lo que necesita. Solo necesita actualizar cada .children propiedad con el resultado de la llamada recursiva antes de regresar.

El valor de retorno es solo el .length de la resultante .children colección, por lo que si hay al menos uno, el objeto se mantiene.

var res = input.filter(function f(o) 
  if (o.value.includes("Hit")) return true

  if (o.children) 
    return (o.children = o.children.filter(f)).length
  
)

const input = [
  
    value: 'Miss1',
    children: [
       value: 'Miss2' ,
       value: 'Hit1', children: [  value: 'Miss3'  ] 
    ]
  ,
  
    value: 'Miss4',
    children: [
       value: 'Miss5' ,
       value: 'Miss6', children: [  value: 'Hit2'  ] 
    ]
  ,
  
    value: 'Miss7',
    children: [
       value: 'Miss8' ,
       value: 'Miss9', children: [  value: 'Miss10'  ] 
    ]
  ,
  
    value: 'Hit3',
    children: [
       value: 'Miss11' ,
       value: 'Miss12', children: [  value: 'Miss13'  ] 
    ]
  ,
  
    value: 'Miss14',
    children: [
       value: 'Hit4' ,
       value: 'Miss15', children: [  value: 'Miss16'  ] 
    ]
  ,
];

var res = input.filter(function f(o) 
  if (o.value.includes("Hit")) return true

  if (o.children) 
    return (o.children = o.children.filter(f)).length
  
)
console.log(JSON.stringify(res, null, 2))


Tenga en cuenta que .includes() en una cadena es ES7, por lo que es posible que deba parchearse para los navegadores heredados. Puedes usar el tradicional .indexOf("Hit") != -1 en su lugar.


Para no mutar el original, cree una función de mapa que copie un objeto y utilícela antes del filtro.

function copy(o) 
  return Object.assign(, o)


var res = input.map(copy).filter(function f(o) 
  if (o.value.includes("Hit")) return true

  if (o.children) 
    return (o.children = o.children.map(copy).filter(f)).length
  
)

Para realmente exprimir el código, podrías hacer esto:

var res = input.filter(function f(o) 
         o.children && (o.children = o.children.filter(f)).length
)

Aunque se pone un poco difícil de leer.

Aquí hay una función que hará lo que estás buscando. Esencialmente probará cada elemento en arr para una coincidencia, luego recursivamente llame al filtro en su children. también Object.assign se utiliza para que el objeto subyacente no cambie.

function filter(arr, term) 
    var matches = [];
    if (!Array.isArray(arr)) return matches;

    arr.forEach(function(i) 
        if (i.value.includes(term)) 
            matches.push(i);
         else 
            let childResults = filter(i.children, term);
            if (childResults.length)
                matches.push(Object.assign(, i,  children: childResults ));
        
    )

    return matches;

Creo que será una solución recursiva. Aquí hay uno que probé.

function find(obj, key) 
  if (obj.value && obj.value.indexOf(key) > -1)
    return true;
  
  if (obj.children && obj.children.length > 0)
    return obj.children.reduce(function(obj1, obj2)
      return find(obj1, key) , ); 
   
  return false;


var output = input.filter(function(obj)
     return find(obj, 'Hit');
 );
console.log('Result', output);

valoraciones y reseñas

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *