Рекурсивно использовать методы прототипа массива - PullRequest
1 голос
/ 18 марта 2019

Я использую структуру бесконечного уровня, похожую на эту:

    {
  "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"
        }
        ]
    }
    ]
}

Где у нас могут быть узлы внутри групп, но также и группы внутри групп.

До сих пор я писал рекурсивные функции каждый раз, когда мне нужно что-то сделать, но код становится довольно непривлекательным.

Мне было интересно, есть ли способ создать версии методов Array.prototype, но настроить их для использования рекурсии

например, чтобы найти любой объект (узел или группу) по идентификатору, у меня есть метод

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)
        }

    }

В реальном мире есть нечто большее, чем просто Id Мне нужно искать / вкладывать. Так как же я могу создать свои собственные функции-прототипы, которые затем я могу вызывать так?

thisGroup.nodes.findIndexRecursively(e => e.id == target)
thisGroup.nodes.findIndexRecursively(e => e.type=="node" && e.someProp == someValue)

Ответы [ 2 ]

2 голосов
/ 18 марта 2019

Лично я бы не добавил это к прототипу, должна делать простая функция.

Вот простой пример, он предполагает, что это все массивы, которые вы хотите рекурсивно пройти и проверить.

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"));
1 голос
/ 18 марта 2019

Вы можете использовать рекурсивную функцию и выполнять поиск с обратным вызовом.

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; }
...