„Ich versuche rekursiv ein Objekt zu suchen, die Zeichenfolgen enthält, Arrays, und andere Objekte, um ein Objekt auf der tiefsten Ebene zu finden (einen Wert zu finden), aber ich bekomme als Ergebnis immer undefiniert. "
var foundIt = findItem('glasses', theCobWeb);
console.log('The item is here: ' + foundIt); // The item is here: undefined
"Der Artikel ist hier ..." - wo?
Nun, was genau willst du als Rückgabewert? Sollte es nur "glasses"
sagen, wenn alles fertig ist? Meiner Meinung nach ist das sinnlos - im Grunde ist es nicht besser, als einfach true
oder false
zurückzugeben.
Ich schrieb diese Funktion vor einer Weile, weil ich einen Haufen von Daten suchen musste, aber auch genau weiß, wo es zusammenpasst.Ich würde das jetzt wahrscheinlich ein wenig überarbeiten (oder zumindest Typ Anmerkungen hinzufügen), aber es funktioniert wie es ist, also hier gehen Sie.
// helpers
const keys = Object.keys
const isObject = x=> Object(x) === x
const isArray = Array.isArray
const rest = ([x,...xs])=> xs
// findDeep
const findDeep = (f,x) => {
let make = (x,ks)=> ({node: x, keys: ks || keys(x)})
let processNode = (parents, path, {node, keys:[k,...ks]})=> {
if (k === undefined)
return loop(parents, rest(path))
else if (isArray(node[k]) || isObject(node[k]))
return loop([make(node[k]), make(node, ks), ...parents], [k, ...path])
else if (f(node[k], k))
return {parents, path: [k,...path], node}
else
return loop([{node, keys: ks}, ...parents], path)
}
let loop = ([node,...parents], path) => {
if (node === undefined)
return {parents: [], path: [], node: undefined}
else
return processNode(parents, path, node)
}
return loop([make(x)], [])
}
// your sample data
var theCobWeb = {biggestWeb: {item: "comb",biggerWeb: {items: ["glasses", "paperclip", "bubblegum"],smallerWeb: {item: "toothbrush",tinyWeb: {items: ["toenails", "lint", "wrapper", "homework"]}}},otherBigWeb: {item: "headphones"}}};
// find path returns {parents, path, node}
let {path, node} = findDeep((value,key)=> value === "glasses", theCobWeb)
// path to get to the item, note it is in reverse order
console.log(path) // => [0, 'items', 'biggerWeb', 'biggestWeb']
// entire matched node
console.log(node) // => ['glasses', 'paperclip', 'bubblegum']
Die grundlegende Intuition hier ist node[path[0]] === searchTerm
komplette Pfad zur angepassten Abfrage
wir den gesamten Schlüsselpfad zu den angepassten Daten. Dies ist nützlich, weil wir genau wissen, wo es auf der Wurzel unserer Suche basiert. Um zu überprüfen, der Pfad korrekt ist, finden Sie in diesem Beispiel
const lookup = ([p,...path], x) =>
(p === undefined) ? x : lookup(path,x)[p]
lookup([0, 'items', 'biggerWeb', 'biggestWeb'], theCobWeb) // => 'glasses'
Unübertroffene Abfrage
Hinweis, wenn wir nach etwas zu suchen, die nicht gefunden wird, wird node
sein undefined
let {path, node} = findDeep((value,key)=> value === "sonic the hog", theCobWeb)
console.log(path) // => []
console.log(node) // => undefined
Suchen nach einem bestimmten Schlüssel/Wert-Paar
Die Suchfunktion empfängt ein value
und key
Argument. Verwenden Sie sie, wie Sie
let {path, node} = findDeep((value,key)=> key === 'item' && value === 'toothbrush', theCobWeb)
console.log(path) // => [ 'item', 'smallerWeb', 'biggerWeb', 'biggestWeb' ]
console.log(node) // => { item: 'toothbrush', tinyWeb: { items: [ 'toenails', 'lint', 'wrapper', 'homework' ] } }
Kurzschluss wünschen - 150cc
Oh, und weil ich dich verderben, findDeep
wird eine frühe Rückkehr geben, sobald die erste Übereinstimmung gefunden wird. Es wird keine Berechnungszyklen verschwenden und weiter durch Ihren Datenstapel gehen, nachdem es die Antwort kennt. Das ist eine gute Sache.
Go erkunden
Mut haben, abenteuerlich sein. Die obige findDeep
-Funktion gibt auch eine parents
-Eigenschaft für zurückgegebenes Objekt. Es ist wahrscheinlich nützlich für Sie in gewisser Hinsicht, aber es ist ein wenig komplizierter zu erklären und nicht wirklich kritisch für die Beantwortung der Frage. Um diese Antwort zu vereinfachen, werde ich nur erwähnen, dass es da ist.
Danke. Sie haben einige sehr nützliche Hinweise zur Säuberung meines Codes hinzugefügt. Das erreicht jedoch nicht vollständig, wonach ich suche. Mein Ziel ist es, den Gegenstand auf der tiefsten Ebene zu finden, nicht in der ersten Instanz. Also in diesem Beispiel, wenn die Brille auch in tinyWeb.items vorhanden wäre, würde ich das zurückgegeben haben, nicht größerWeb. – Phil
@Phil Ich werde bearbeiten! –
@Phil dies scheint ein bisschen schwierig als Was ist, wenn es "Brille" in zwei verschachtelten Objekte, aber nicht die gleiche Tiefe, sollte die Funktion irgendwelche von ihnen oder nur die tiefe zurückgeben? –