Estoy tratando de escribir una función de búsqueda para encontrar elementos de elementos coincidentes de una matriz potencialmente anidada ( sin tener que aplanar la matriz primero) y estoy tratando de escribir de forma FP.
Aquí está mi intento:
const nestedArray = [ [{ id: 1 }], [{ id: 2 }], [{ id: 3 }, [{ id: 4 }]], { id: 5 }, ] function findTarget(arr, predicate) { const helper = ([x, ...xs]) => x === undefined ? null : predicate(x) ? x : Array.isArray(x) ? helper(x) ?? helper(xs) : helper(xs) return helper(arr) } findTarget(nestedArray, (item) => item.id === 5)Creo que funciona, pero no es muy legible y estoy seguro de que hay mejores formas de escribir una función de este tipo.
Así es como implementaría esto usando recursividad:
function findTarget(value, predicate) { const isArray = Array.isArray(value); // Base case: if value is not array and predicate matches, we found a match if (!isArray) { if (predicate(value)) return value; return null; } // value must be an array, so run recursion and see if value exists for (const item of value) { const foundItem = findTarget(item, predicate); if (foundItem !== null) { return foundItem; } } // nothing found return null; }hace lo mismo que tu código y imo se ve más limpio.
Dado que su ejemplo está llamando al predicate(x) en primer lugar, devolverá un falso positivo al hacer coincidir una array con una propiedad id: 5 , por lo que Array.isArray(x) debe ir primero para evitar esto:
const nestedArray = [ Object.assign([{ id: 1 }], { id: 5 }), [{ id: 2 }], [{ id: 3 }, [{ id: 4 }], null, [[{ id: 5 }]]], { id: 6 }, ] function findTargetLoop (arr, match) { if (!Array.isArray(arr)) return arr && match(arr) ? arr : null; let item, i = 0; while (!(item = findTargetLoop(arr[i++], match)) && i < arr.length); return item ?? null; } const findTargetFunc = (arr, match, next) => (next = ([item, ...rest]) => Array.isArray(item) ? next(item) ?? next(rest) : item && match(item) ? item : rest.length ? next(rest) : null)(arr); const match = item => item.id === 5; console.log('with iterations', findTargetLoop(nestedArray, match)); console.log('pure functional', findTargetFunc(nestedArray, match));Aquí hay un enfoque que se me ocurre. Utiliza la función init como valor centinela para distinguir si el elemento que se busca ya se ha encontrado. Antes de regresar, invoca el valor acumulado que es () => undefined o () => curr capturando el primer elemento que coincide con el predicado.
const flatFind = (array, predicate) => { const init = () => undefined const reducer = (prev, curr) => ( prev === init ? Array.isArray(curr) ? curr.reduce(reducer, init) : predicate(curr) ? () => curr : init : prev ) return array.reduce(reducer, init)() } const nestedArray = [ [{ id: 1 }], [{ id: 2 }], [{ id: 3 }, [{ id: 4 }]], { id: 5 }, ] console.log(flatFind(nestedArray, item => item.id === 5))