Ett smidigt sätt att hitta den första träffen på något i en array är Array.prototype.find. Här är ett försök med att använda det (depth-first):
function findCat(catName, items) {
return items.find((item) => {
switch (item.get("type")) {
case "cat":
return item.get("name") === catName;
case "group":
return findCat(catName, item.get("cats"));
}
});
}
Det funkar bra när katten vi söker ligger direkt i arrayen, men när den ligger i en grupp returnerar funktionen hela gruppen som innehåller katten istället för bara katten.
Detta är en begränsning av .find
– du kan hitta en befintlig sak (Cat | Group
) i listan men inte byta typ (Cat
).
En del språk (men inte JavaScript) har en .findMap
-funktion för detta. Istället för att returnera en boolean i callbacken, så returnerar man undefined
för en icke-träff och valfritt annat värde vid träff. Det slutgilitga värdet blir antingen det valfria värdet eller undefined
.
Här är findCat
med findMap
:
function findCat(catName, items) {
return findMap(items, (item) => {
switch (item.get("type")) {
case "cat":
return item.get("name") === catName ? item : undefined;
case "group":
return findCat(catName, item.get("cats"));
}
});
}
Så här kan man implementera findMap
:
function findMap(items, f) {
for (const item of items) {
const value = f(item);
if (value !== undefined) {
return value;
}
}
return undefined;
}
Om du absolut inte vill använda en for
-loop någonstans kan man göra något i den här stilen istället:
function findMap(items, f) {
return findMapHelper(items, f, 0);
}
function findMapHelper(items, f, index) {
if (index >= items.length) {
return undefined;
}
const item = items[index];
const value = f(item);
return value !== undefined ? value : findMapHelper(items, f, index + 1);
}