我有一个非常大的数组,看起来与此类似
var counts = ["gfdg 34243","jhfj 543554",....] //55268 elements long
这是我目前的循环
var replace = "";
var scored = 0;
var qgram = "";
var score1 = 0;
var len = counts.length;
function score(pplaintext1) {
qgram = pplaintext1;
for (var x = 0; x < qgram.length; x++) {
for (var a = 0, len = counts.length; a < len; a++) {
if (qgram.substring(x, x + 4) === counts[a].substring(0, 4)) {
replace = parseInt(counts[a].replace(/[^1-9]/g, ""));
scored += Math.log(replace / len) * Math.LOG10E;
} else {
scored += Math.log(1 / len) * Math.LOG10E;
}
}
}
score1 = scored;
scored = 0;
} //need to call the function 1000 times roughly
我必须多次遍历此数组,并且我的代码运行缓慢。我的问题是循环这个数组的最快方法是什么,所以我可以节省尽可能多的时间。
答案 0 :(得分:3)
您的counts
数组似乎是与其关联的唯一字符串和值的列表。改为使用对象,键入唯一的字符串,例如:
var counts = { gfdg: 34243, jhfj: 543554, ... };
这将大规模通过将O(n)
内部循环替换为O(1)
对象密钥查找来消除对log(1 / n) = -log(n)
内部循环的需求,从而提高性能。
此外,避免分裂 - log(1/len) * Math.LOG10E
- 并在循环外移动循环不变量。您的if
实际上是每次传递中添加的常量,但在第一个Math.log(replace)
分支中您还需要考虑var len = Object.keys(counts).length;
function score(text) {
var result = 0;
var factor = -Math.log(len) * Math.LOG10E;
for (var x = 0, n = text.length - 4; x < n; ++x) {
var qgram = text.substring(x, x + 4);
var replace = counts[qgram];
if (replace) {
result += Math.log(replace) + factor;
} else {
result += len * factor; // once for each ngram
}
}
return result;
}
,这在日志数学中意味着添加它。
P.S。避免使用外部范围的状态变量来获得分数!我认为以下正确复制了您的评分算法:
{{1}}