Hay una matriz inicial que debe mapearse y filtrarse al mismo tiempo:
let data = [ { "id": 1, "parentId": null, "dxId": "1_id", "dxParentId": null, "defName": "group1" }, { "id": 12, "parentId": null, "dxId": "12_id", "dxParentId": null, "defName": "группа3" }, { "id": 8, "parentId": 1, "dxId": "1_id/13", "dxParentId": "1_id", "defName": "group4" }, { "id": 5, "parentId": 1, "dxId": "1_id/20", "dxParentId": "1_id", "defName": "user1" }, { "id": 5, "parentId": 1, "dxId": "1_id/20", "dxParentId": "12_id", "defName": "user1" }, ];Filtro por la presencia de la propiedad parentide y recopilo la matriz de cadenas resultante (no la matriz inicial de objetos).
originalmente lo hice a través del método de reducción:
resultArr = data.reduce((filtered, obj) => { if( obj.dx_parentId !== null) { if(!(filtered.includes(obj.dxParentId))) { filtered.push(obj.dxParentId); } } return filtered; }, []); console.log(resultArr , 'result'); // ['1_id', '12_id'] 'result'luego descubrí por mí mismo que esto se puede hacer con el método de matriz flatMap
resultArr = data.flatMap((obj) => obj.dxParentId !== null ? [obj.dxParentId] : []); console.log(resultArr , 'result'); //['1_id', '1_id', '12_id'] 'result'Si nota que en el caso de reducir uso filtrado (arreglo acumulativo) , hago una verificación adicional usando include y obtengo el resultado que necesito.
La pregunta es ¿cómo hacer lo mismo a través de flatMap? ¿Es posible acceder al resultado acumulado en cada iteración?
Además: ¿alguien puede decirme qué es mejor usar para resolver este caso, en términos de optimización? mb para cada uno? gracias de antemano
No puede acceder a la matriz que se está construyendo en flatMap . En el mapeo, y también en el mapeo con aplanamiento, se supone que la devolución de llamada devuelve un valor que depende solo del elemento en particular.
Es posible que simplemente no quiera usar reduce en absoluto para un algoritmo imperativo como este:
const resultArr = []; for (const obj of data) { if (obj.dxParentId !== null) { if (!resultArr.includes(obj.dxParentId)) { filtered.push(obj.dxParentId); } } } console.log(resultArr, 'result');Sin embargo, para obtener valores únicos de una matriz , existe una forma mucho mejor (más simple y más eficiente):
const resultArr = Array.from(new Set(data.map(obj => obj.dxParentId).filter(id => id !== null))); console.log(resultArr, 'result');Entonces, si bien no puede ver la matriz que se está construyendo mientras se construye, puede crear un objeto justo fuera del mapa plano y usarlo para rastrear qué ID ha agregado o no.
const seen = {}; const resultArr = data.flatMap((obj) => { const id = obj.dxParentId; if (id in seen) return []; if (id !== null) { seen[id] = true; return [id]; } return []; }); console.log(resultArr, "result"); //['1_id', '1_id', '12_id'] 'result'En cuanto a la complejidad del tiempo y el espacio, esta solución es mucho más rápida, pero ocupa mucho más espacio (en la mayoría de los casos, es una buena compensación).
Array.include() atraviesa toda la matriz y tiene una complejidad de tiempo de O(n). key in object tiene una complejidad de tiempo constante, pero construir el objeto es O (n) espacio.
En mi opinión, la mejor solución posible sería combinar la búsqueda instantánea de un objeto con el alcance de reducir.
const resultArr = data.reduce( (acc, obj) => { const id = obj.dxParentId; const { seen, filtered } = acc; if (id in seen) return acc; if (id !== null) { seen[id] = true; filtered.push(id); } return acc; }, { seen: {}, filtered: [] } ).filtered; console.log(resultArr, "result"); // ['1_id', '12_id'] 'result'Esta solución tiene la misma complejidad de tiempo y espacio que el mapa plano, pero el objeto visto se vuelve elegible para la recolección de basura tan pronto como finaliza el método de reducción, por lo que esos posibles problemas de espacio no son una preocupación tan grande.