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

3

我有以下对象数组:

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

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

这是我使用underscore尝试过的,但它不起作用:

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

我希望通过删除特定id的文件对象来更新列表。

到目前为止,所有的解决方案都是创建原始副本。有没有办法直接从原始列表中切掉它?


@RoryMcCrossan 打错字了,抱歉。 - adam78
请解释“如果我同时拥有项目 ID 和文件 ID,那么如何删除文件对象?”您的意思是独立删除提供的 ID 和文件 ID 的文件,还是删除具有给定项目 ID 的文件? - Hassan Imam
5个回答

1
你实际上可以完全不使用下划线来完成它:

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)
    


我想要更新原始列表。如果我只有文件ID,我该如何实现? - adam78

0

顺便提一下:您也可以使用新的对象扩展运算符在ES6中完成此操作,并过滤掉那些与id不匹配的对象。当然,这将返回一个新对象而不是从现有对象中删除对象,但这可能是一个选项。

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

演示

以前没有Babel插件是不可能实现的,但现在看起来已经在现代浏览器中实现了。


0

你可以用本地的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);
        }
    }
};

你的第一个示例在ES5中的等效代码是什么? - adam78

0

你可以使用组合_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>


最好创建一个repl.it而不是使用代码片段,因为后者由于未定义_而无法运行。 - Dexygen
我添加了“_”并使代码运行,但似乎无法更改嵌套数组。如果我将“id:3”更改为“id:119”,它会从该层中删除,但是当它要从第二层中删除时(例如“id:10”),它不起作用。 - Theraot
@samnu 只应该删除具有该ID的文件对象。 - adam78

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


如果我同时拥有项目 ID 和文件 ID,我该如何实现相同的操作。因此,如果我有一个巨大的列表,它只需要检查一个项目是否包含匹配的文件 ID,如果是,则删除该文件。最好使用 ES5。 - adam78
你可以先按项目 ID 进行过滤,然后再按文件 ID 进行过滤。这样就能解决问题了。你想从匹配的项目中删除文件 ID 吗? - Hassan Imam
是的,我需要删除匹配的文件。文件ID在整个对象数组中是唯一的。但是如果我知道项目ID,则无需检查整个项目列表,然后还要检查每个项目的文件数组以删除一个文件。我需要一个更新后的对象数组而不是副本。您的foreach将不必要地循环遍历整个列表。 - adam78
您想删除给定项目 ID 内的文件吗? - Hassan Imam
让我们在聊天中继续这个讨论 - Hassan Imam
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接