【问题标题】:How to optimize the computation speed in array.forEach in node.jsnode.js中如何优化array.forEach的计算速度
【发布时间】:2019-02-05 10:55:31
【问题描述】:

我有一段代码简单地遍历两个数组,对于第一个数组的每个元素,它会在第二个数组中找到相关元素,只更改第一次出现并删除剩余的元素。

 /**
     * The aggregation data structure:
     * "_id": {
     * "geometry": geometry,
     * "dups": [
     *    "5b3b25b4e54029249c459bfc", keep only the fisrt element in allDocs
     *    "5b3b25b4e54029249c459e65", delete it from allDocs
     *    "5b3b25b4e54029249c459d7d"   delete it from allDocs
     *   ],
     * "dupsProp": [  ], array of all properties of duplicatePoints
     * "count": 3
     */
var aggregationRes =[46,000 objects]
var allDocs =[345,000 objects]
aggregationRes.forEach(function (resElem, counter) {
        console.log(counter + "/" + aggregationRes.length)
        //Delete objects in allDocs based on dups array except the first one
        var foundIndex = allDocs.findIndex(x => x._id.toString() == resElem.dups[0]);
                //assign the mergedProperties
        allDocs[foundIndex].properties = resElem.dupsProp;
        //delete the remaining ids in Docs from dups array 
        resElem.dups.forEach(function (dupElem, index) {
            var tmpFoundIndex = allDocs.findIndex(x => x._id.toString() == resElem.dups[index + 1]);
            if (tmpFoundIndex !== -1) {
                allDocs.splice(tmpFoundIndex, 1)
            }
        })
    })

这个脚本运行了将近 4 个小时。如您所见,计算非常简单,但由于 allDocs 数组很大,因此需要很长时间。如果有人给我一个关于如何减少计算时间的提示,那就太好了。 在此先感谢

【问题讨论】:

  • 使allDocs按id索引,这样就不用每次都findIndex了。并且避免在大数组上做很多小的splices,而是将它们标记为删除,然后一次性将它们全部删除。
  • (另外:为如此大的数据使用数据库:-)
  • 不要执行x._id.toString() 46K * 345K * (dupecount + 1) 次之类的操作,而是在创建一个新属性时迭代 allDocs 数组,即 x._id.toString()(仅限 345K 操作)。 x._id 是整个对象吗?还是一些数字/字符串 ID?
  • 是否可以简单地使用resElem.dups = [resElem.dups[0]]; 而不是resElem.dups.forEach 迭代?您希望得到一个只包含旧数组中第一个条目的新数组,对吗?看起来很简单
  • 您的聚合数据结构示例是错误的/具有误导性。看起来 _id 属性是整个内部对象。这是 node.js,您使用的是 mongodb(“javascript ObjectID”的第一个搜索结果)吗?如果是这样,可能希望将这些标签添加到您的问题中。我想有一种更有效的方法可以使用您的数据库来做到这一点。

标签: javascript arrays optimization foreach computation


【解决方案1】:

借鉴 Bergi 的想法,我们通过 id 对文档进行索引,以避免查找昂贵的索引:

var allDocs =[345,000 objects]
var aggregationRes =[46,000 objects]
var allDocsIndexed = {};

allDocs.forEach(function(doc){
    allDocsIndexed[doc._id.toString()] = doc;
});

aggregationRes.forEach(function (resElem, counter) {
    allDocsIndexed[resElem.dups[0]].properties = resElem.dupsProp;
    for (var i = 1; i < resElem.dupsProp.length; i++) {
        delete allDocsIndexed[resElem.dupsProp[i]];
    }
});

var allUndeletedDocs = allDocs.filter(doc => allDocsIndexed.hasOwnProperty(doc_id.toString()));

请注意,对于 javascript,这是一种有效的解决方案,但如果提供了更多详细信息,使用 mongodb 功能可能会存在更好的解决方案。

【讨论】:

  • 嘿...您的解决方案非常完美。逆天。呜呜呜,我简直不敢相信。这是supppppppppper快。只需不到一分钟,它就完成了我过去在 3 到 4 小时内完成的整个计算。我不知道人们通常对索引数组说什么,但是现在通过您的示例,我非常了解它。多谢。只是一个简单的问题:我没有使用最后一行(过滤),因为我已经有了所有结果。你为什么要过滤它们?
  • @MaryamKoulaei 我们只从 allDocsIndexed 中删除了键,我们从未从 allDocs 中删除任何内容。因此,我没有删除,而是过滤以获取未删除的内容
猜你喜欢
  • 2015-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-08
  • 2021-09-20
  • 1970-01-01
相关资源
最近更新 更多