JavaScript 中循环的性能问题
Performance Issues with loops in JavaScript
我的 JavaScript 代码存在巨大的性能问题。
我尝试在 OPL 中为 Cplex 模型预处理数据,代码写在 JavaScript.
我已经尝试通过添加第一个 if 子句 (if A[1][3]=""
, A[1][k] =""
for every k
> 3) 来加快速度,但它仍然需要我的计算机超过处理这段代码需要 2 小时...
Jnr = 1000,
Mnr = 35;
while (j <= Jnr) {
while (i <= Mnr) {
while (k <= Mnr) {
if (A[j][k] == "") {
break;
} else if (A[j][k] == I[i].name) {
counter[j][i] = counter[j][i] + 1;
}
k = k + 1;
}
k = 1;
i = i + 1;
}
i = 1;
j = j + 1;
}
j = 1;
有没有办法加快这个过程?
感谢您的帮助
您可以通过首先创建一个用于将名称映射到索引 i 的映射来节省一级循环。此外,indexOf
可能比在内循环中检查空字符串更快:
// Preprocessing
const names = {};
for (let i = 1; i <= Mnr; i++) names[I[i].name] = i;
// Main
for (let j = 1; j <= Jnr; j++) {
const row = A[j];
const counterRow = counter[j];
let m = row.indexOf("")-1;
if (m < 0) m = Jnr;
for (let k = 1; k <= m; k++) {
let i = names[row[k]];
if (i !== undefined) counterRow[i]++;
}
}
注意:您的数组的值从索引 1 开始。这对于 JavaScript(以及许多其他语言)来说是非典型的。考虑填充数组,使第一个条目位于 0,最后一个条目位于 Jnr - 1
,...等等。这也可能会增加一点性能,因为解析器的优化器在这种情况下可能会更好地工作。
为大循环使用脚本不是一个好主意。如果您直接在 OPL 中编写,这会快得多:
int Jnr = 1000;
int Mnr = 35;
tuple t
{
string name;
}
t I[i in 1..Mnr]=<"A">;
string A[i in 1..Jnr][j in 1..Mnr]=((i+j)%2==0)?"A":"B";
int counter[1..Jnr][1..Mnr];
execute
{
var i=1;
var j=1;
var k=1;
while (j <= Jnr) {
while (i <= Mnr) {
while (k <= Mnr) {
if (A[j][k] == "") {
break;
} else if (A[j][k] == I[i].name) {
counter[j][i] = counter[j][i] + 1;
}
k = k + 1;
}
k = 1;
i = i + 1;
}
i = 1;
j = j + 1;
}
j = 1;
}
int counter2[i in 1..Jnr][j in 1..Mnr]=sum(k in 1..Mnr) (I[k].name==A[i][k]);
execute
{
counter2;
}
assert forall(i in 1..Jnr,j in 1..Mnr) counter[i][j]==counter2[i][j];
counter 在我的机器上需要 9 秒,而 counter2 需要 0.3 秒
我的 JavaScript 代码存在巨大的性能问题。 我尝试在 OPL 中为 Cplex 模型预处理数据,代码写在 JavaScript.
我已经尝试通过添加第一个 if 子句 (if A[1][3]=""
, A[1][k] =""
for every k
> 3) 来加快速度,但它仍然需要我的计算机超过处理这段代码需要 2 小时...
Jnr = 1000,
Mnr = 35;
while (j <= Jnr) {
while (i <= Mnr) {
while (k <= Mnr) {
if (A[j][k] == "") {
break;
} else if (A[j][k] == I[i].name) {
counter[j][i] = counter[j][i] + 1;
}
k = k + 1;
}
k = 1;
i = i + 1;
}
i = 1;
j = j + 1;
}
j = 1;
有没有办法加快这个过程?
感谢您的帮助
您可以通过首先创建一个用于将名称映射到索引 i 的映射来节省一级循环。此外,indexOf
可能比在内循环中检查空字符串更快:
// Preprocessing
const names = {};
for (let i = 1; i <= Mnr; i++) names[I[i].name] = i;
// Main
for (let j = 1; j <= Jnr; j++) {
const row = A[j];
const counterRow = counter[j];
let m = row.indexOf("")-1;
if (m < 0) m = Jnr;
for (let k = 1; k <= m; k++) {
let i = names[row[k]];
if (i !== undefined) counterRow[i]++;
}
}
注意:您的数组的值从索引 1 开始。这对于 JavaScript(以及许多其他语言)来说是非典型的。考虑填充数组,使第一个条目位于 0,最后一个条目位于 Jnr - 1
,...等等。这也可能会增加一点性能,因为解析器的优化器在这种情况下可能会更好地工作。
为大循环使用脚本不是一个好主意。如果您直接在 OPL 中编写,这会快得多:
int Jnr = 1000;
int Mnr = 35;
tuple t
{
string name;
}
t I[i in 1..Mnr]=<"A">;
string A[i in 1..Jnr][j in 1..Mnr]=((i+j)%2==0)?"A":"B";
int counter[1..Jnr][1..Mnr];
execute
{
var i=1;
var j=1;
var k=1;
while (j <= Jnr) {
while (i <= Mnr) {
while (k <= Mnr) {
if (A[j][k] == "") {
break;
} else if (A[j][k] == I[i].name) {
counter[j][i] = counter[j][i] + 1;
}
k = k + 1;
}
k = 1;
i = i + 1;
}
i = 1;
j = j + 1;
}
j = 1;
}
int counter2[i in 1..Jnr][j in 1..Mnr]=sum(k in 1..Mnr) (I[k].name==A[i][k]);
execute
{
counter2;
}
assert forall(i in 1..Jnr,j in 1..Mnr) counter[i][j]==counter2[i][j];
counter 在我的机器上需要 9 秒,而 counter2 需要 0.3 秒