web-dev-qa-db-fra.com

Recherche récursive JavaScript dans un objet JSON

J'essaie de renvoyer un nœud spécifique dans une structure d'objet JSON qui ressemble à ceci

{
    "id":"0",
    "children":[
        {
            "id":"1",
            "children":[...]
        },
        {
            "id":"2",
            "children":[...]
        }
    ]
}

C'est donc une relation parent-enfant qui ressemble à un arbre. Chaque node a un identifiant unique . J'essaie de trouver un node spécifique comme celui-ci.

function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        currentNode.children.forEach(function (currentChild) {            
            findNode(id, currentChild);
        });
    }
}  

J'exécute la recherche par exemple avec findNode("10", rootNode). Mais même si la recherche trouve une correspondance, la fonction retourne toujours undefined. J'ai le mauvais pressentiment que la fonction récursive ne s'arrête pas après avoir trouvé le match et continue à exécuter un retourne finalement undefined car dans la dernière exécution récursive, elle n'atteint pas un point de retour, mais je ne sais pas comment résoudre ce problème.

S'il vous plaît aider! 

17
Dropout

Lors d'une recherche récursive, vous devez renvoyer le résultat en le renvoyant. Vous ne retournez pas le résultat de findNode(id, currentChild), cependant.

function findNode(id, currentNode) {
    var i,
        currentChild,
        result;

    if (id == currentNode.id) {
        return currentNode;
    } else {

        // Use a for loop instead of forEach to avoid nested functions
        // Otherwise "return" will not work properly
        for (i = 0; i < currentNode.children.length; i += 1) {
            currentChild = currentNode.children[i];

            // Search in the current child
            result = findNode(id, currentChild);

            // Return the result if the node has been found
            if (result !== false) {
                return result;
            }
        }

        // The node has not been found and we have no more options
        return false;
    }
}
33
Butt4cak3
function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        var result;
        currentNode.children.forEach(function(node){
            if(node.id == id){
                result = node;
                return;
            }
        });
        return (result ? result : "No Node Found");
    }
}
console.log(findNode("10", node));

Cette méthode renverra le nœud s'il est présent dans la liste des nœuds. Mais cela va parcourir tous les fils d'un noeud, car nous ne pouvons pas casser le flux forEach avec succès. Une meilleure implémentation ressemblerait à celle ci-dessous.

function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        var result;
        for(var index in currentNode.children){
            var node = currentNode.children[index];
            if(node.id == id)
                return node;
            findNode(id, node);
        }
        return "No Node Present";
    }
}
console.log(findNode("1", node));
4
Triode

J'utilise le suivant

var searchObject = function (object, matchCallback, currentPath, result, searched) {
    currentPath = currentPath || '';
    result = result || [];
    searched = searched || [];
    if (searched.indexOf(object) !== -1 && object === Object(object)) {
        return;
    }
    searched.Push(object);
    if (matchCallback(object)) {
        result.Push({path: currentPath, value: object});
    }
    try {
        if (object === Object(object)) {
            for (var property in object) {
                if (property.indexOf("$") !== 0) {
                    //if (Object.prototype.hasOwnProperty.call(object, property)) {
                        searchObject(object[property], matchCallback, currentPath + "." + property, result, searched);
                    //}
                }
            }
        }
    }
    catch (e) {
        console.log(object);
        throw e;
    }
    return result;
}

Ensuite, vous pouvez écrire

searchObject(rootNode, function (value) { return value != null && value != undefined && value.id == '10'; });

Maintenant, cela fonctionne sur des références circulaires et vous pouvez faire correspondre n'importe quel champ ou combinaison de champs que vous aimez en modifiant la fonction matchCallback.

1
Peter

J'ai vraiment aimé une recherche d'arbres! Une arborescence est une structure de données extrêmement commune pour la plupart des tâches structurées complexes d'aujourd'hui. Donc, je viens d'avoir une tâche similaire pour le déjeuner aussi. J'ai même fait des recherches approfondies, mais je n'ai rien trouvé de nouveau! Donc, ce que j'ai pour vous aujourd'hui, c'est "Comment j'ai implémenté cela dans la syntaxe JS moderne":

// helper
find_subid = (id, childArray) => {
    for( child of childArray ) {
        foundChild = find_id( i, child ); // not sub_id, but do a check (root/full search)!
        if( foundChild ) // 200 
            return foundChild;
    }
    return null; // 404
}

// actual search method
find_id = (id, parent) => (id == parent.id) : parent : find_subid(id, parent.childArray);
0
xakepp35