通过键删除嵌套结构中的对象

时间:2019-03-22 10:11:38

标签: javascript arrays object ecmascript-6 key

我有一个带有对象的数组,可以有多个子对象,这些子对象与父对象具有相同的结构,基本上只是对象嵌套。

我想知道如何通过键删除其中一个对象。例如,我想删除ID为1(嵌套在另一个对象的子级数组中)的对象

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

抚养孩子

有可能吗?如果删除带有子对象的对象,那么子对象会移到根目录?

我尝试过

我尝试重做以下函数,该函数从我的数据结构中返回所有ID,因此它获取ID,如果有子代,则获取这些子代内部的ID。但是,如何删除具有该ID的对象?

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

6 个答案:

答案 0 :(得分:1)

您可以这样:

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)

答案 1 :(得分:1)

您只需要使用递归function调用并使用 Array#splice() method 来删除搜索到的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);

编辑:

如果要将所有已删除的项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);

答案 2 :(得分:0)

像这样?递归迭代并在找到具有您ID的对象时进行拼接

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)

答案 3 :(得分:0)

以递归方式浏览对象并根据指定的谓词删除该对象:

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

答案 4 :(得分:0)

此递归函数可满足您的需求:

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

答案 5 :(得分:0)

您可以使用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);