Удалить объект во вложенной структуре по ключу - PullRequest
2 голосов
/ 22 марта 2019

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

Мне интересно, как я могу удалить один из объектов по ключу. Например, я хочу удалить объект с id: 1 (который вложен в дочерний массив другого объекта)

const data = [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]

Перемещение детей вверх

Возможно ли это? Если объект с дочерними объектами удален, то дочерние объекты перемещаются в корень?

Я пробовал

Я попытался переделать следующую функцию, которая возвращает все идентификаторы из моей структуры данных, поэтому он выбирает идентификатор, а если есть дети, выбирает идентификаторы внутри этих детей. Но как мне удалить объект с таким идентификатором?

export function flattenFindAttribute (data, attribute) {
  return data.map(item => [item[attribute], ...flattenFindAttribute(item.children)]).flat()
}

Ответы [ 6 ]

1 голос
/ 22 марта 2019

Вам просто нужно использовать рекурсивный вызов function и использовать Array#splice() метод , чтобы удалить найденный object.

Вот как должен быть ваш код:

function removeId(data, id) {
  data.forEach((o, i) => {
    if (o.id && o.id === id) {
      data.splice(i, 1);
      return true;
    } else if (o.children) {
      removeId(o.children, id);
    }
  });
}

Демо:

const data = [{
    id: 2,
    children: [{
      id: 1,
      children: []
    }]
  },
  {
    id: 3,
    children: [],
  }
];

function removeId(data, id) {
  data.forEach((o, i) => {
    if (o.id && o.id === id) {
      data.splice(i, 1);
      return true;
    } else if (o.children) {
      removeId(o.children, id);
    }
  });
}

removeId(data, 1);
console.log(data);

Edit:

Если вы хотите поместить весь удаленный элемент children в его родительский массив children, вам просто нужно передать третий параметр вашей функции, чтобы отслеживать родительский элемент object:

function removeId(data, id, parent) {
  data.forEach((o, i) => {
    if (o.id && o.id === id) {
      if (parent) {
        o.children.forEach(c => parent.children.push(c));
      }
      data.splice(i, 1);
      return true;
    } else if (o.children) {
      removeId(o.children, id, o);
    }
  });
}

Демо-версия:

var data = [{
    id: 2,
    children: [{
      id: 1,
      children: [1, 2]
    }]
  },
  {
    id: 3,
    children: [],
  }
];

function removeId(data, id, parent) {
  data.forEach((o, i) => {
    if (o.id && o.id === id) {
      if (parent) {
        o.children.forEach(c=> parent.children.push(c));
      }
      data.splice(i, 1);
      return true;
    } else if (o.children) {
      removeId(o.children, id, o);
    }
  });
}

removeId(data, 1);
console.log(data);
1 голос
/ 22 марта 2019

Вы можете сделать это так:

const data = [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]

let deletedObj = {}

function deleteAtId(arr, deleteId) {
  const rs = []
  arr.forEach(({id, children}) => {
    if(id !== deleteId) {
      if(!children.length) {
        rs.push({id, children})
      } else {
        const tmp = deleteAtId(children, deleteId)
        rs.push({id, children: tmp})
      }
    } else deletedObj = {id, children}
  })
  return rs
}

const rs = [...deleteAtId(data, 1), {...deletedObj}]

console.log(rs)
0 голосов
/ 22 марта 2019

Этого можно добиться, используя Array.reduce с рекурсией для детей.

Пример:

const data = [
  { id: 1, children: [{ id: 2, children: [] }] },
  {
    id: 2,
    children: [
      {
        id: 1,
        children: [],
      },
    ],
  },
  {
    id: 3,
    children: [],
  },
  {
    id: 4,
    children: [
      {
        id: 2,
        children: [
          {
            id: 2,
            children: [
              {
                id: 1,
                children: [],
              },
              {
                id: 2,
                children: [],
              },
            ],
          },
        ],
      },
    ],
  },
];

function removeBy(data, predicate) {
  return data.reduce((result, item) => {
    if (!predicate(item.id)) {
      const newItem = { ...item };
      if (item.children.length > 0) {
        newItem.children = removeBy(item.children, predicate);
      }
      result.push(newItem);
    }
    return result;
  }, []);
}

const predicate = value => value === 1;
const result = removeBy(data, predicate);

console.log(result);
0 голосов
/ 22 марта 2019

Эта рекурсивная функция работает для ваших нужд:

function rotateChildren(array, key) {
   if (!array || !array.length) {
      return array;
   }

   return array.filter(child => {
      if (child) {
         child.children = rotateChildren(child.children, key);
         return child.id !== key;
      }

      return !!child;
   });
}

const data = [
   {
      id: 2,
      children: [
         {
            id: 1,
            children: []
         }
      ]
   },
   {
      id: 3,
      children: [],
   }
];

console.log(rotateChildren(data, 1));
console.log(rotateChildren(data, 2));
console.log(rotateChildren(data, 3));
0 голосов
/ 22 марта 2019

Рекурсивно исследовать объект и удалять в соответствии с указанным предикатом:

const data =[...Array(4)].map(()=> [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]);

function deleteObj(parent, predicate) {
  if (predicate(parent)) {
    return true;
  }
  if (typeof parent === 'object') {
    if (Array.isArray(parent)) {
      for (let i = 0; i < parent.length; i++) {
        if (deleteObj(parent[i], predicate)) {
          parent.splice(i, 1);
          i--;
        }
      } 
    } else {
      Object.keys(parent).forEach(key => deleteObj(parent[key], predicate) && delete parent[key]);
    }
  }
  return false;
}

console.log('from array:', data[0]);

const test1 = data[1];
const test2 = data[2];
const test3 = data[3];

console.log('delete node with id === 1');
deleteObj(test1, node => node.id === 1);
console.log(test1);

console.log('delete node with id === 3');
deleteObj(test2, node => node.id === 3);
console.log(test2);

console.log('delete node with non empty children');
deleteObj(test3, node => node.children && node.children.length > 0);
console.log(test3);
0 голосов
/ 22 марта 2019

Как то так? Он рекурсивно повторяет и склеивает, когда находит объект с вашим идентификатором

function removeObject(data, id){
  data.forEach(point =>{
    if(point.children.length > 0){
      removeObject(point.children, id);
    }
    const index = data.findIndex(x => x.id == id);
    if(index > -1){
      data.splice(index ,1);
    }
  });
  return data;
}

const data = [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]

removeObject(data, 1);

console.log(data)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...