¿Cuál es la mejor manera de filtrar una matriz de objetos en función de varias condiciones de propiedad y conservar el orden original? Entonces, lo que tiene que suceder es filtrar la matriz en función de estas dos condiciones:
En otras palabras, deje solo los válidos y los que tengan el número de versión más alto (el número de versión puede ser cualquiera).
const arr = [ { name: 'John', invalid: false, version: 1 }, { name: 'John', invalid: false, version: 2 }, { name: 'John', invalid: true, version: 1 }, { name: 'John', invalid: true, version: 5 }, { name: 'John', invalid: true, version: 2 }, { name: 'Samuel', invalid: false, version: 1 }, { name: 'Samuel', invalid: false, version: 2 }, { name: 'Samuel', invalid: true, version: 1 }, ];
a...
const arr = [ { name: 'John', invalid: false, version: 2 }, { name: 'Samuel', invalid: false, version: 2 } ];
¡Gracias por adelantado!
Puedes hacerlo usando Array.prototype.reduce .
Actualice el objeto correspondiente a un name
en particular solo si:
const data = [ { name: "John", invalid: false, version: 1 }, { name: "John", invalid: false, version: 2 }, { name: "John", invalid: true, version: 1 }, { name: "John", invalid: true, version: 5 }, { name: "John", invalid: true, version: 2 }, { name: "Samuel", invalid: false, version: 1 }, { name: "Samuel", invalid: false, version: 2 }, { name: "Samuel", invalid: true, version: 1 }, ]; const result = Object.values( data.reduce((acc, d) => { if (d.invalid) return acc; if (!acc[d.name] || d.version > acc[d.name].version) { acc[d.name] = d; } return acc; }, {}) ); console.log(result);
En TS, puede crear tipos separados para datos válidos e inválidos utilizando el tipo de unión.
type ValidData = { name: string; invalid: false; version: number }; type InvalidData = { name: string; invalid: true; version: number }; const data: (ValidData | InvalidData)[] = [ { name: "John", invalid: false, version: 1 }, { name: "John", invalid: false, version: 2 }, { name: "John", invalid: true, version: 1 }, { name: "John", invalid: true, version: 5 }, { name: "John", invalid: true, version: 2 }, { name: "Samuel", invalid: false, version: 1 }, { name: "Samuel", invalid: false, version: 2 }, { name: "Samuel", invalid: true, version: 1 }, ]; const result = Object.values( data.reduce((acc: { [name: string]: ValidData }, d) => { if (d.invalid) return acc; if (!acc[d.name] || d.version > acc[d.name].version) { acc[d.name] = d; } return acc; }, {}) ); console.log(result);
Recomiendo hacer esto en varias etapas. Suponiendo que el orden de la matriz no es importante, puede .sort
de modo que la versión más reciente sea la primera, y realizar un seguimiento de las que ha agregado, y también filtrar las no válidas. Algo como esto:
function filterThing(thing) { const added = new Set(); return thing.sort((a, b) => b.version - a.version).filter((item) => { if (thing.invalid || added.has(thing.name)) { return false; } added.add(thing.name); return true; } }
Si necesita tener los artículos en otro orden, puede ordenar después de eso. Si necesita conservar el orden original de los elementos, ese es un algoritmo más complicado.
Simplemente podría usar una tabla de búsqueda, esto es en tiempo de ejecución O (n).
Básicamente, itere una vez a través de la matriz, recuerde para cada nombre válido la versión más alta que vio y luego use esa tabla como filtro para la matriz original.
const lookup = {} as Record<string, {name: string, version: number, invalid: boolean}>; arr.forEach((it) => { const stored = lookup[it.name]; if (stored) { if (!it.invalid && it.version > stored.version) { lookup[it.name] = it; } } else { lookup[it.name] = it; } }) const filtered = arr.filter((it) => { const stored = lookup[it.name]; const result = !it.invalid && it.version === stored.version; if (result) { //if no duplicates wanted delete lookup[it.name]; } return result; });