简体   繁体   English

无需使用for循环即可更快地迭代JavaScript数组的方法

[英]Faster approach to iterate JavaScript array without using for loop

Here is a sample of the JSON data that I'm trying to parse. 这是我要解析的JSON数据示例。

{
    "tags": [{
        "name": "SQOP_SPD",
        "results": [{
            },
            "values": [
                [1499771383876, 0, 0],
                [1499771384800, 0, 0],
                [1499771385885, 10, 0],
                [1499771386893, 0, 0],
                [1499771388867, 0, 0],
                [1499771389879, 10, 0],
                [1499771390878, 0, 0],
                [1499771391787, 0, 0],
                [1499771392870, 0, 0],
                [1499771394015, 0, 0],
                [1499771394955, 0, 0],
                [1499771395800, 0, 0],
                [1499771396882, 0, 0],
                [1499771397904, 0, 0],
                [1499771399906, 0, 0]
            ],
            "attributes": {
                "VId": ["9499"],
            }
        }],
        "stats": {
            "rawCount": 15
        }
    }
}

I'm iterating through the values array using a for loop and checking if a particular timestamp is present. 我正在使用for loop遍历values数组for loop并检查是否存在特定的时间戳。

var items = dataa['tags'][j]['results'][0]['values'];
for (var k = 0; k < items.length; k++) {
    if (items[k] == sortedTimeStampList[i]) {
          // some code
    }
}

The page begins to hang when there are like 10000000 entries in the the values array. 当values数组中有10000000个条目时,页面开始挂起。

Is there a faster approach to check for a timestamp in the values array. 有没有一种更快的方法来检查values数组中的时间戳。

Honestly, the fastest form of loop in Javascript is the for loop, with a cached index as you currently have. 老实说,JavaScript中最快的循环形式是for循环,它具有您当前拥有的缓存索引。 Your performance will vary quite greatly depending on the browser you are in and the available resources on your machine. 根据您所使用的浏览器和计算机上的可用资源,您的性能会有很大的不同。

I believe you have an architectural flaw in your application. 我相信您的应用程序存在体系结构缺陷。 Do you need all 10000000 entries at once? 您一次需要所有10000000个条目吗? A binary search will help you out for what you need (as suggested by someone else), but I would argue that there probably isn't a need to load and loop all entries like you are trying to do. 二进制搜索将帮助您找到所需的信息(由其他人建议),但是我认为您可能不需要像尝试执行的那样加载和循环所有条目。

Consider lazily loading your entries as you need them instead of all at once. 考虑按需懒惰地加载条目,而不是一次加载所有条目。 Load the data when you need it, as you need it. 根据需要加载数据。 It sounds like you're currently hitting memory limitations, 10000000 entries is a lot of data to work with (especially if you have arrays of complex objects). 听起来您当前遇到内存限制,10000000条目是要处理的大量数据(尤其是如果您有复杂对象的数组)。

I recommend looking into Service Workers which are made for more computational/heavy tasks that are run in a separate thread from the browser, but they're not supported that well just yet, so probably not an option for you if you're creating a front-facing application where you don't control what browsers access it. 我建议您研究服务人员,这些服务人员是为在浏览器的单独线程中运行的更多计算/繁重任务而设计的,但是目前尚不支持它们,因此如果您要创建前端应用程序,您无需控制浏览器即可访问它。

One possibility would be iterating slower ( so that it doesnt hang): 一种可能是迭代速度变慢(这样它就不会挂起):

function find(callback,value,start=0){
 for (var k = 0; k+start < items.length; k++) {
  if (items[k+start][0] === value) {
      callback(items[k+start]);
  }
  if(k==100){
   setTimeout(find,0,callback,value,start+k);
   break;
 }
}

Usecase: 用例:

find(console.log,512627172);

Or if you just want to get a certain timestamp you could use a map: 或者,如果您只想获取特定的时间戳,则可以使用地图:

var map=new Map(items.map(el=>[el[0],el.slice(1)]));
console.log(map.get(5293842838));

And if you just want to check the existance of a certain timestamp you could also create a Set out of your array (better performance concerning finding) : 而且,如果您只想检查某个时间戳记的存在,则还可以在数组中创建一个Set(与查找有关的性能更好):

var set=new Set(items.map(el=>el[0]));
set.has(5293842838);

Here is a native solution. 这是一个本机解决方案。 I get about 150ms when looping through a single dataset. 遍历单个数据集时,我得到了大约150ms时间。

 var obj = { "tags": [{ "name": "SQOP_SPD", "results": [{ "values": [], "attributes": { "VId": ["9499"] } }], "stats": { "rawCount": 15 } }] }; //Date for timing var d = Date.now(); //Add 10000000 rows while (obj.tags[0].results[0].values.length < 10000000) { obj.tags[0].results[0].values.push([1499771383876 + obj.tags[0].results[0].values.length, 0, 0]); } console.log("spent " + (Date.now() - d) + "ms on adding rows"); //Native model for comparison d = Date.now(); //Target is number 100 from the end var target = obj.tags[0].results[0].values[obj.tags[0].results[0].values.length - 7]; //Find index var iAmNative = obj.tags[0].results[0].values. findIndex(function(a) { return a[0] == target[0]; }); //Log output console.log("spent " + (Date.now() - d) + "ms on succeeding natively, result:", obj.tags[0].results[0].values[iAmNative], " index:", iAmNative); obj = null; 

Or even faster using a binary search approach: 使用二进制搜索方法甚至更快:

 var obj = { "tags": [{ "name": "SQOP_SPD", "results": [{ "values": [], "attributes": { "VId": ["9499"] } }], "stats": { "rawCount": 15 } }] }; //Date for timing var d = Date.now(); //Add 10000000 rows while (obj.tags[0].results[0].values.length < 10000000) { obj.tags[0].results[0].values.push([1499771383876 + obj.tags[0].results[0].values.length, 0, 0]); } console.log("spent " + (Date.now() - d) + "ms on adding rows"); //The binary search algorithm var binarySearch = (function() { /** * compare_complex * * @param {(number | string)} a * @param {(number | string)} b * @returns {number} */ function compare_complex(a, b) { return a.toString().localeCompare(b.toString()); } /** * compare_number * * @param {number} a * @param {number} b * @returns {number} */ function compare_number(a, b) { return a - b; } /** * binarySearch * * @param {IBinarySearch} [args={ list: [], target: '' }] * @returns {number} */ function binarySearch(args) { if (args === void 0) { args = { list: [], target: '' }; } var params = { list: [], key: null, target: '', threshold: 10, complex: true }; for (var key in args) { if (args.hasOwnProperty(key) && params.hasOwnProperty(key)) { params[key] = args[key]; } } var max = params.list.length - 1; var maxKey = (params.key == null ? params.list[max] : params.list[max][params.key]); var min = 0; var minKey = (params.key == null ? params.list[min] : params.list[min][params.key]); if (minKey == params.target) { return min; } if (maxKey == params.target) { return max; } var compare = (params.complex === true ? compare_complex : compare_number); while (max - min >= params.threshold) { var diff = max - Math.floor((max - min) / 2); var diffKey = (params.key == null ? params.list[diff] : params.list[diff][params.key]); var cmp = compare(diffKey, params.target); if (cmp == 0) { return diff; } else if (cmp < 0) { min = diff; } else { max = diff; } } if (params.key != void 0) { var index = params.list.slice(min, max).map(function(m) { return m[params.key]; }).indexOf(params.target); } else { var index = params.list.slice(min, max).indexOf(params.target); } if (index >= 0) { return index + min; } return index; } return binarySearch; })(); //Binary model for comparison d = Date.now(); //Target is number 100 from the end var target = obj.tags[0].results[0].values[obj.tags[0].results[0].values.length - 7][0]; //Find index var iAmBinary = binarySearch({ list: obj.tags[0].results[0].values, target: target, key: 0 }); //Log output console.log("spent " + (Date.now() - d) + "ms on searching binarily, result:", obj.tags[0].results[0].values[iAmBinary], "index:", iAmBinary); //Release memory obj = null; 

I consistently gets less than 10ms search time with the binary approach. 我始终使用二进制方法获得少于10ms搜索时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 遍历 object 或数组是否更快? - Is it faster to iterate / loop over an object or an array? JavaScript:在 for 循环中遍历数组? - JavaScript: Iterate through array in for loop? 如何使用NodeJS在没有循环的情况下迭代对象内部的数组 - How to iterate array inside object without loop using NodeJS 如何在不使用 for 循环的情况下迭代 FormData entries() 数组 - How to iterate over a FormData entries() array without using for-loop 为什么使用循环从数组的开始迭代到结束比从开始到结束和结束开始更快地迭代? - Why is using a loop to iterate from start of array to end faster than iterating both start to end and end to start? 我如何在JavaScript中使用数组时迭代第二个for循环 - How I can iterate second for loop while using array in JavaScript 在不使用嵌套for循环的情况下迭代JavaScript数组 - Iterate over a JavaScript array without using nested for-loops 使用带有键数组的数字 for 循环是否比在 JavaScript 中使用 for-in 循环遍历 object 更快? - Is using a numeric for loop with an array of keys faster than iterating over an object with a for-in loop in JavaScript? 为什么要按大小更快地迭代数组 - Why iterate by array with size faster 使用javascript在对象中搜索数组而不使用循环 - Search through array in an object using javascript without using a loop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM