I am trying to write a find function to find items from matched items from a potentially nested array (without having to flat the array first) and I am trying to write in a FP way.
Here is my attempt:
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)
I think it works but it is not super readable and I am sure there are better ways to write such a function.
CodePudding user response:
Here's how I would implement this using recursion:
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;
}
does the same thing that your code does and imo looks cleaner.
CodePudding user response:
Since your example is calling predicate(x)
in the first place, it will return a false positive when matching an array
with an id: 5
property, so the Array.isArray(x)
should go first to avoid this:
const nestedArray = [
Object.assign([{ id: 1 }], { id: 5 }),
[{ id: 2 }],
[{ id: 3 }, [{ id: 4 }]],
{ id: 5 },
]
function findTarget (arr, predicate) {
if (!Array.isArray(arr))
return predicate(arr) ? arr : null;
let item, i = 0;
for (; !item && i < arr.length;)
item = findTarget(arr[i ], predicate);
return item ?? null;
}
const item = findTarget(nestedArray, (item) => item.id === 5);
console.log(item);