Найти последний вложенный объект n раз по его значению - PullRequest
1 голос
/ 05 июня 2019

Пытался решить эту задачу сам, но я сдаюсь.Что бы я ни пытался, это не сработало.Поэтому решил обратиться за помощью сюда.

Есть объект:

var obj = [{
    "name": "111",
    "type": "folder",
    "expanded": true,
    "id": 0,
    "items": [
      {
        "name": "222",
        "type": "folder",
        "expanded": true,
        "id": 1,
        "items": [
          {
            "name": "333",
            "type": "folder",
            "expanded": true,
            "id": 2,
            "items": [
              {
                "name": "444",
                "type": "folder",
                "expanded": true,
                "id": 3,
                "items": [],
                "itemIndex": 0,
                "index": 0
              }
            ],
            "itemIndex": 0,
            "index": 0
          }
        ],
        "itemIndex": 0,
        "index": 0
      }
    ],
    "itemIndex": 0,
    "index": 0
  }]

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

Учитывая приведенный выше код, скажем, мне нужна функция, которая, только имея ее ID илиname, может вставить еще один объект в массив «items» следующего объекта:

{
    "name": "444",
    "type": "folder",
    "expanded": true,
    "id": 3,
    "items": [],
    "itemIndex": 0,
    "index": 0
}

Другими словами, у меня есть вводимый текст и кнопка.После ввода текста и нажатия этой кнопки функция должна определить самый последний уровень заданного объекта и нажать только что созданный объект (тот же набор ключей, ID должен быть +1 от унаследованного объекта, name должно быть введено в строку текстового поля)

Надеюсь, я объяснил проблему как можно более подробно.

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Вам понадобится функция, которая сначала найдет самый глубокий узел:

/**
 * Return [depth, item] where item is the deepest subnode of node.
 */
function find_deepest(node, depth=0) {
    if (node.items.length === 0) return [depth, node];

    return node.items.map(child => find_deepest(child, depth+1)).sort().reverse()[0];
}

, затем просто:

const [depth, node] = find_deepest(obj, 0);
node.items.push({...});

update: только что понял, что ваш obj - это список, поэтому с приведенным выше кодом он будет выглядеть так:

const [depth, node] = obj.map(child => find_deepest(child)).sort().reverse()[0]);

, который не является лучшим интерфейсом.

Разделение рекурсии на две функции, одну для случая узла и одну для случая массива, и оборачивание их в функцию, ответвляющуюся по типу, даст вам лучший интерфейс:

console.log(find_deepest(obj));

Подробности смотрите во фрагменте ниже (я расширил ваш объект второй веткой с пустыми элементами:

var obj = [{
    "name": "111", "type": "folder", "expanded": true, "id": 0, "itemIndex": 0, "index": 0,
    "items": [{
        "name": "222", "type": "folder", "expanded": true, "id": 1, "itemIndex": 0, "index": 0,
        "items": [{
            "name": "333", "type": "folder", "expanded": true, "id": 2, "itemIndex": 0, "index": 0,
            "items": [{
                "name": "444", "type": "folder", "expanded": true, "id": 3,"itemIndex": 0, "index": 0,
                "items": []
            }],
        }, {
            "name": "555", "type": "folder", "expanded": true, "id": 3,"itemIndex": 0, "index": 0,
            "items": [{
                "name": "666", "type": "folder", "expanded": true, "id": 3,"itemIndex": 0, "index": 0,
                "items": [{
                    "name": "777", "type": "folder", "expanded": true, "id": 3,"itemIndex": 0, "index": 0,
                    "items": [],
                }]
            }]
        }]
    }]
}];

function find_deepest(val, depth=0) {
    function _find_deepest_node(node, depth) {
        if (node.items.length === 0) return [depth, node];
        return _find_deepest_array(node.items, depth + 1);
    }

    function _find_deepest_array(arr, depth) {
        return arr.map(child => _find_deepest_node(child, depth)).sort().reverse()[0];
    }

    if (Array.isArray(val)) {
        return _find_deepest_array(val, depth)[1];  // get the node, not the depth..
    } else {
        return _find_deepest_node(val, depth)[1];
    }
}

console.log(find_deepest(obj));
0 голосов
/ 05 июня 2019

Я бы создал рекурсивную функцию, которая будет выдвигать данные в конец массива, как только он найдет правильный идентификатор.Если он не находит идентификатор, перейдите к следующему пункту.Это выглядело бы так:

function pushItem(id, data, obj) {
  for (let itm of obj) {
    let r = itm.items.find(i => i.id == id)
    if(!r) return pushItem(id, data, itm.items)
    r.items.push(data)
  }
}

pushItem(3, {abc: 1}, obj)
console.log(obj)

Вот рабочий пример:

var obj = [{
  "name": "111",
  "type": "folder",
  "expanded": true,
  "id": 0,
  "items": [{
    "name": "222",
    "type": "folder",
    "expanded": true,
    "id": 1,
    "items": [{
      "name": "333",
      "type": "folder",
      "expanded": true,
      "id": 2,
      "items": [{
        "name": "444",
        "type": "folder",
        "expanded": true,
        "id": 3,
        "items": [],
        "itemIndex": 0,
        "index": 0
      }],
      "itemIndex": 0,
      "index": 0
    }],
    "itemIndex": 0,
    "index": 0
  }],
  "itemIndex": 0,
  "index": 0
}]

function pushItem(id, data, obj) {
  for (let itm of obj) {
    let r = itm.items.find(i => i.id == id)
    if (!r) return pushItem(id, data, itm.items)
    r.items.push(data)
  }
}

pushItem(3, { name: "123123", id: 20, items: [] }, obj)
console.log(obj)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...