Underscore.js - 从嵌套数组中删除项目?

Underscore.js - Delete item from nested array?

我有以下对象数组:

var list = [{
  "id": 119,
  "files": []
}, {
  "id": 126,
  "files": [{
    "id": 9,
    "filename": "test1.docx",
  }, {
    "id": 10,
    "filename": "test2.docx",
  }]
}]

如何通过删除具有特定 ID 的文件来更新列表(文件 ID 是唯一的)例如我想删除 ID 为 10 的文件。

这是我迄今为止使用下划线尝试过的方法,但它不起作用:

_.each(list.item, function(item, idx) {
  if (_.findWhere(item.files, { id: 10 })) {
    //remove file from files array
    files.splice(idx, 1); 
  }
});

我想通过删除具有特定 ID 的文件对象来更新列表

到目前为止所有的解决方案都创建了原始解决方案的副本。有没有办法简单的从原来的列表中拼接出来?

您可以通过结合使用 _without 和 findWhere 来实现。我猜您想删除该 ID 的整个数组。

var list = [
               {
                 "id": 119,
                 "files": []
                },
                {
                 "id": 126,
                 "files": [
                     {
                       "id": 9,
                       "filename": "test1.docx",
                     },
                     {
                       "id": 10,
                       "filename": "test2.docx",
                     }
                   ]
                }
             ];
list = _.without(list, _.findWhere(list, {
  id: 119
}));
console.log(list);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

事实上,你完全可以不使用下划线:

var list = [{"id": 119, "files": []}, {"id": 126, "files": [{"id": 9, "filename": "test1.docx"}, {"id": 10, "filename": "test2.docx", }]}]

var itemId = 126
var fileId = 10

var out = list.map(function(item) {
    if (item.id === itemId) {
        // Copy the item in order to not mutate the original object
        var itemCopy = Object.assign({}, item)
        itemCopy.files = itemCopy.files.filter(function(file) { return file.id !== fileId })
        return itemCopy
    } else return item
})

console.log(out)
    

顺便说一句:您还可以在 ES6 中使用新的对象展开运算符并过滤掉那些 不匹配 ID 的对象。当然,这 returns 是一个新对象,而不是从现有对象中删除对象,但它可能是您的一种选择。

const out = list.map(el => {
  return {
    ...el,
    files: el.files.filter(f => f.id !== 9)
  }
});

DEMO

如果没有 Babel 插件,这在以前是不可能的,但现在看起来它已经登陆了现代浏览器。

你可以用原生 javascript 这样做:

1) 如果我只有文件ID,如何删除文件对象? (文件 ID 是唯一的)

// ES6 version
const deleteFile1Es6 = (fileId) => {
    for(item of list){
        const file = item.files.filter(file => file.id === fileId)[0];
        if(file != null){
            item.files.splice(item.files.indexOf(file), 1);
            break;
        }
    }
};

// ES5 version
function deleteFile1Es5(fileId) {
    for(var i = 0; i < list.length; i++){
        var item = list[i];
        var fileFoundIndex = -1;
        for(var j = 0; j < item.files.length; j++){
            var file = item.files[j];
            if(file.id === fileId){
                fileFoundIndex = j;
                break;
            }
        }
        if(fileFoundIndex !== -1){
            item.files.splice(fileFoundIndex, 1);
            break;
        }
    }
}

2) 如果我同时拥有项目 ID 和文件 ID,那么如何删除文件对象?

const deleteFile2Es6 = (itemId, fileId) => {
    const item = list.filter(item => item.id === itemId)[0];
    if(item != null){
        const file = item.files.filter(file => file.id === fileId)[0];
        if(file != null){
            item.files.splice(item.files.indexOf(file), 1);
        }
    }
};

您可以使用 array#forEach 遍历 list 数组,然后使用 array#filter 获取所有没有文件 ID 的文件并重新分配给文件数组每份工作。

var list = [{ "id": 119, "files": [] }, { "id": 126, "files": [{ "id": 9, "filename": "test1.docx", }, { "id": 10, "filename": "test2.docx", }] }];
var deleteWithFileId = (fileId) => list.forEach((o) => {
  o.files = o.files.filter(({id}) => fileId !== id);
});
deleteWithFileId(10)
console.log(list);

ES 5 代码

var list = [{ "id": 119, "files": [] }, { "id": 126, "files": [{ "id": 9, "filename": "test1.docx" }, { "id": 10, "filename": "test2.docx" }] }];
var deleteWithFileId = function (fileId) {
  return list.forEach(function (o) {
    o.files = o.files.filter(function (obj) {
      return fileId !== obj.id;
    });
  });
};
deleteWithFileId(10);
console.log(list);

要删除文件和项目 ID,您可以先对项目 ID 进行过滤,然后您可以从中对文件进行过滤。

var list = [{ "id": 119, "files": [] }, { "id": 126, "files": [{ "id": 9, "filename": "test1.docx", }, { "id": 10, "filename": "test2.docx", }] }];
var deleteWithItemAndFileId = (itemId, fileId) => {
  list.forEach(o => {
    if (o.id === itemId) {
      o.files = o.files.filter(({id}) => id !== fileId);
    }
  })
}

deleteWithItemAndFileId(126, 10)
console.log(list);