Как рекурсивно обновить вложенный массив, используя javascript - PullRequest
0 голосов
/ 23 февраля 2020

У меня есть массив, который содержит: name , id (id представляет путь в массиве) и children (необязательно). У детей есть та же структура, что и у массива. Каждый элемент может иметь дочерних элементов, а его дочерние элементы могут иметь своих собственных дочерних элементов et c. Потенциально это может быть глубоко вложенный массив. Я хочу обновить идентификаторы для всех вложенных детей в зависимости от нового индекса. У меня есть функция, которая принимает массив и новый индекс. Функция вызывает себя рекурсивно, если элемент содержит дочерние элементы. Например, я передаю массив и индекс, равный 1. В этом случае я ожидаю замены '2.children [0] .children [0] 'на '1.children [0] .children [0]'

По некоторым причинам вложенные дети не обновляются правильно. Когда я отлаживаю код, я вижу, что newValue генерируется правильно, но в конце я получаю массив со старыми идентификаторами.

  {
    name: 'Cat',
    id: '0',
  },
  {
    name: 'Dog',
    id: '1',
  },
  {
    name: 'Rabbit',
    id: '2',
    children: [
      {
        name: 'Little Rabbit Child',
        id: '2.children[0]',
        children: [
          { name: 'Little Rabbit Child One', id: '2.children[0].children[0]',children: [{ name: "Rat", id: "2.children[0].children[0].children[0]"}] },
          { name: 'Little Rabbit Child Two', id: '2.children[0].children[1]' },
          { name: 'Little Rabbit Child Three', id: '2.children[0].children[2]' },
        ],
      },
      { name: 'Little Rabbit Son', id: '2.children[1]' },
      { name: 'Little Rabbit Daughter', id: '2.children[2]' },
    ],
  },
  {
    name: 'Elephant',
    id: '3',
    children: [{ name: 'Little Elephant', id: '3.children[0]' }],
  },
];


const updateChildrenIds = (childrenData = [], index) => {
  const newData = childrenData.map(value => {
    const { id, children = [] } = value;
    if (children.length) updateChildrenIds(children, index);
    const splitIds = id.split('.');
    splitIds[0] = index;
    const newId = splitIds.join('.');

    const newValue = {...value, id: newId}

    return newValue;
  });

  return newData;
};


const data = updateChildrenIds(testData[2].children, 1);

ожидаемый результат будет:

[
      {
        name: 'Little Rabbit Child',
        id: '1.children[0]',
        children: [
          { name: 'Little Rabbit Child One', id: '1.children[0].children[0]',children: [{ name: "Rat", id: "1.children[0].children[0].children[0]"}] },
          { name: 'Little Rabbit Child Two', id: '1.children[0].children[1]' },
          { name: 'Little Rabbit Child Three', id: '1.children[0].children[2]' },
        ],
      },
      { name: 'Little Rabbit Son', id: '1.children[1]' },
      { name: 'Little Rabbit Daughter', id: '1.children[2]' },
    ]

Я был бы признателен если бы кто-то мог помочь мне с этим

Ответы [ 2 ]

0 голосов
/ 23 февраля 2020

Проблема в вашем коде заключается в том, что, пока вы вызываете updateChildren(children, index), вы ничего не делаете с результатом.

Этот код создает новый массив и не изменяет ваш старый объект в место. (Я искренне одобряю это!) Но это означает, что когда вы звоните детям updateChildren, вам действительно нужно что-то сделать с результатом.

Вот твик к вашему коду, который это исправит.

const updateChildrenIds = (childrenData = [], index) => {
  const newData = childrenData.map(value => {
    const { id, children} = value; // no default value for children
    // removed the recursive call from here
    const splitIds = id.split('.');
    splitIds[0] = index;
    const newId = splitIds.join('.');

    const newValue = {...value, id: newId}
    if (children) {  // moved here
      newValue.children = updateChildrenIds(children, index)
    }

    return newValue;
  });

  return newData;
};


const testData = [{name: "Cat", id: "0"}, {name: "Dog", id: "1"}, {name: "Rabbit", id: "2", children: [{name: "Little Rabbit Child", id: "2.children[0]", children: [{name: "Little Rabbit Child One", id: "2.children[0].children[0]", children: [{name: "Rat", id: "2.children[0].children[0].children[0]"}]}, {name: "Little Rabbit Child Two", id: "2.children[0].children[1]"}, {name: "Little Rabbit Child Three", id: "2.children[0].children[2]"}]}, {name: "Little Rabbit Son", id: "2.children[1]"}, {name: "Little Rabbit Daughter", id: "2.children[2]"}]}, {name: "Elephant", id: "3", children: [{name: "Little Elephant", id: "3.children[0]"}]}]

console .log (updateChildrenIds (testData [2] .children, 1))
.as-console-wrapper {min-height: 100% !important; top: 0}

Но если бы я написал это, я бы сделал это по-другому. Итак, вот еще один подход, который более точно соответствует нормам функционального программирования:

const updateIds = (nodes, baseId) => 
  nodes .map (({id, children, ...rest}) => ({
    ...rest,
    id: id .replace (/^\d+/, baseId),
    ... (children && {children: updateIds (children, baseId)})
  }))

const testData = [{name: "Cat", id: "0"}, {name: "Dog", id: "1"}, {name: "Rabbit", id: "2", children: [{name: "Little Rabbit Child", id: "2.children[0]", children: [{name: "Little Rabbit Child One", id: "2.children[0].children[0]", children: [{name: "Rat", id: "2.children[0].children[0].children[0]"}]}, {name: "Little Rabbit Child Two", id: "2.children[0].children[1]"}, {name: "Little Rabbit Child Three", id: "2.children[0].children[2]"}]}, {name: "Little Rabbit Son", id: "2.children[1]"}, {name: "Little Rabbit Daughter", id: "2.children[2]"}]}, {name: "Elephant", id: "3", children: [{name: "Little Elephant", id: "3.children[0]"}]}]

console .log (updateIds (testData [2] .children, 1))
.as-console-wrapper {min-height: 100% !important; top: 0}

Наряду с несколько более простой общей структурой этот код также заменяет ваши split / replace / join инструкции одним regex.replace .

Ни один из подходов не обновляет исходную структуру данных. Если вам нужно сделать это, вы можете присвоить этот результат обратно соответствующему пути в вашей структуре или создать функцию, которая делает эквивалент, при этом разделяя как можно больше структуры. Это не сложно. Функция assocPath в недавнем ответе , вдохновленная Ramda , подойдет.

0 голосов
/ 23 февраля 2020

Когда вы возвращаете значение,

return Object.assign({}, newData)

или

return {...newData}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...