J'utilise une structure de niveau infini, similaire à celle-ci :

    {
  "name": "Group1",
  "type": "group",
  "nodes": [
    {
      "name": "Node1",
      "type": "node",
      "someproperty": "somevalue1"
    },
    {
      "name": "Group2",
      "type": "group",
      "nodes": [
        {
          "name": "Node2",
          "type": "node",
          "someproperty": "somevalue2"
        },
        {
          "name": "Node3",
          "type": "node",
          "someproperty": "somevalue3"
        }
        ]
    }
    ]
}

Où nous pouvons avoir des nœuds à l'intérieur des groupes, mais aussi des groupes à l'intérieur des groupes.

Jusqu'à présent, j'ai écrit des fonctions récursives à chaque fois que j'ai besoin de faire quelque chose, mais le code devient assez étrange.

Je me demandais s'il existait un moyen de créer des versions des méthodes Array.prototype mais de les personnaliser pour utiliser la récursivité

Par exemple pour trouver n'importe quel objet (nœud ou groupe) par identifiant, j'ai une méthode

findNode(target, thisGroup) {

    if (typeof thisGroup == "undefined") {
        thisGroup = this;
    }

    // Am I the element?
    if (thisGroup.id == target) {
        return thisGroup;
    }

    // Look for element in my nodes
    var elementIx = thisGroup.nodes.findIndex(e => e.id == target);
    if (elementIx > 0) {
        // Found the element - return it
        return thisGroup.nodes[elementIx];
    }

    // Not found. Do I contain a group?
    var elementIx = thisGroup.nodes.findIndex(e => e.type == "group");

        if (elementIx > 0) {
            var nestGroup = thisGroup.nodes[elementIx];
            // If so, nest into this group and look again
            return this.findValue(target, nestGroup)
        }

    }

Dans le monde réel, il y a plus que Id que j'ai besoin de rechercher/d'imbriquer. Alors, comment puis-je créer mes propres fonctions prototypes que je peux ensuite appeler comme ça ?

thisGroup.nodes.findIndexRecursively(e => e.id == target)
thisGroup.nodes.findIndexRecursively(e => e.type=="node" && e.someProp == someValue)
1
Janine Rawnsley 18 mars 2019 à 13:08

2 réponses

Meilleure réponse

Personnellement, je n'ajouterais pas cela au prototype, une simple fonction devrait suffire.

Voici un exemple simple, il suppose que ce sont tous les tableaux que vous souhaitez parcourir et vérifier de manière récursive.

const data = [{"name":"Group1","type":"group","nodes":[{"name":"Node1","type":"node","someproperty":"somevalue1"},{"name":"Group2","type":"group","nodes":[{"name":"Node2","type":"node","someproperty":"somevalue2"},{"name":"Node3","type":"node","someproperty":"somevalue3"}]}]}];


function rfind(arr, callback) {
  for (const a of arr) {
    const f = callback(a);
    if (f) return a;
    if (!f) {
      for (const o of Object.values(a)) {
        if (Array.isArray(o)) {
          const f2 = rfind(o, callback);
          if (f2) return f2;
        }
      }
    }
  }
}


console.log(rfind(data, f => f.name==="Node1"));
console.log(rfind(data, f => f.name==="Node3"));
2
Keith 18 mars 2019 à 10:27

Vous pouvez utiliser une fonction récursive et rechercher avec un rappel.

function find(node, cb) {
    var result;
    if (cb(node)) return node;
    if (node.nodes) node.nodes.some(o => result = find(o, cb));
    return result;
}

var node = { name: "Group1", type: "group", nodes: [{ name: "Node1", type: "node", someproperty: "somevalue1" }, { name: "Group2", type: "group", nodes: [{ name: "Node2", type: "node", someproperty: "somevalue2" }, { name: "Node3", type: "node", someproperty: "somevalue3" }] }] },
    find1 = find(node, ({ type, someproperty }) => type === 'node' && someproperty === 'somevalue2'),
    find2 = find(node, ({ name, type }) => name === 'Group2' && type === 'group');

console.log(find1);
console.log(find2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
1
Nina Scholz 18 mars 2019 à 10:28