Javascript — удаление объекта из вложенного массива

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня есть массив объектов, каждый объект должен иметь ключ и заголовок, но дочерние элементы необязательны, и они могут быть вложенными, я могу иметь дочерние элементы внутри дочерних элементов много раз. Я хочу удалить некоторый объект по указанному значению ключа (например, ключ 677). Я пробовал с фильтром, но я удаляю только первый уровень. Также пробовал рекурсию, но не уверен, правильно ли я это сделал.

 const data = [{
    key: '1',
    title: 'title 1',
    children: [{
      key: '098',
      title: 'hey',
      children: [{
        key: '677',
        title: 'child'
      }]
    }]
  },
  {
    key: '123',
    title: 'tile 111'
  },
  {
    key: '345',
    title: 'something'
  }
];

const rem = '677';

const del = (el) => {
  if (!el.children) {
    return el.key !== rem;
  } else {
    if (el.key !== rem) {
      del(el.children);
      return el;
    }
  }
};
const res = data.filter((el) => {
  return del(el);
});

console.log(res);  

Комментарии:

1. 1. возникает синтаксическая ошибка с первыми дочерними элементами — дочерние элементы — это массив прямо сейчас. 2. опубликуйте желаемый результат.

2. Ваш верхний уровень children — это массив объектов, поэтому добавьте фигурные скобки

3. Пробовали ли вы какие-либо рекурсивные решения? Также было бы неплохо, если бы вы опубликовали код фильтра, который работал только на первом уровне.

Ответ №1:

Я предполагаю, что ваше существующее решение похоже

 const data = [
  {
    key: '1',
    title: 'title 1',
    children: [{
      key: '098',
      title: 'hey',
      children: [{ key: '677', title: 'child'}]
    }]
  },
  { key: '123', title: 'tile 111' },
  { key: '345', title: 'something' }
];

function removeByKey(arr, removingKey){
  return arr.filter( a => a.key !== removingKey);
}
  

Таким образом, он работает на первом уровне, но не глубоко.

Просто измените его так, чтобы он выполнял задания

 function removeByKey(arr, removingKey){
  return arr.filter( a => a.key !== removingKey).map( e => {
    return { ...e, children: removeByKey(e.children || [], removingKey)}
  });
}
  

Небольшое предупреждение, для свойства children не будет установлено значение [] для каждого элемента, не имеющего дочерних элементов.

Итак, как это работает? Ну, вместо того, чтобы сохранять приемлемые элементы такими, какие они есть, мы создаем копию, используя {...e} это эквивалентно {key:e.key, title:e.title, children:e.children} в данном случае.

Мы знаем, как принудительно переопределить дочерние свойства removeByKey(e.children || [], removingKey) , поэтому мы вызываем метод рекурсивно. Не функция работает глубоко.

Ответ №2:

Я бы использовал рекурсивный подход с findIndex и splice . Использование some позволит завершить работу кода без прохождения по всему дереву.

 const data = [{
    key: '1',
    title: 'title 1',
    children: [{
      key: '098',
      title: 'hey',
      children: [{
        key: '677',
        title: 'child'
      }]
    }]
  },
  {
    key: '123',
    title: 'tile 111'
  },
  {
    key: '345',
    title: 'something'
  }
];

const removeKey = (data, key) => {
  // look to see if object exists
  const index = data.findIndex(x => x.key === key);
  if (index > -1) {
    data.splice(index, 1); // remove the object
    return true
  } else {
    // loop over the indexes of the array until we find one with the key
    return data.some(x => {
      if (x.children) {
        return removeKey(x.children, key);
      } else {
        return false;
      }
    })
  }
}

console.log(removeKey(data, '677'))
console.log(JSON.stringify(data));  

Ответ №3:

Вы можете использовать простую рекурсию, чтобы добиться цели:

 const data = [
  {
    key: '1',
    title: 'title 1',
    children: [
     {
      key: '098',
      title: 'hey',
      children: [{ key: '677', title: 'child'}]
     }
    ]
  },
  { key: '123', title: 'tile 111' },
  { key: '345', title: 'something' }
];

function removeByKey(key, arr) {
  // loop through all items of array
  for(let i = 0; i < arr.length; i  ) {
    // if array item has said key, then remove it
    if(arr[i].key === key) {
      arr.splice(i, 1);
    } else if(typeof(arr[i].children) !== "undefined") {
      // if object doesn't have desired key but has children, call this function 
      // on the children array
      removeByKey(key, arr[i].children);
    }
  }
}

removeByKey('098', data);

console.log(data);
  

Это может быть немного легче понять, чем другой предоставленный ответ.