JavaScript 在循环中改变数组

JavaScript mutating arrays in loop

我想使用JavaScript复制数组中的某些数组,例如:

var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
var res2 = [];
for(var z in res) {
  var row = res[z];
  var keys = row[0].split(',')
  for(var y in keys) {
    var key = keys[y];
    res2.push([key,row[1]/keys.length,row[2]/keys.length]);
  }
}
/* 
[ [ '1', 33.333333333333336, 16.666666666666668 ],
  [ '2', 33.333333333333336, 16.666666666666668 ],
  [ '3', 33.333333333333336, 16.666666666666668 ],
  [ '4', 37.5, 5 ],
  [ '5', 37.5, 5 ],
  [ '6', 20, 90 ] ]
*/

数组真的非常长,是否可以就地执行此操作(res,无需 res2)?

你可以用 Array.reduce

var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
res = res.reduce(function(a, b){
   var parts = b[0].split(',');
   parts.forEach(function(i){
     a.push([i, b[1]/parts.length, b[2]/parts.length]);
   });
   return a;
}, []);

不过,我相信这还是吃双倍内存:)

另一个解决方案(res2,但更经济):
它一个一个地获取源实体,对其进行处理,然后 gc 允许清理内存...

var res2 = [];
while (res.length) {
    var cur = res.shift();
    var ids = cur[0].split(',')
    ids.forEach(function(i){
      res2.push(i, cur[1]/ids.length, cur[2]/ids.length);
    });
}

您可以使用 reduce 类似这样的函数

var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
var r = res.reduce(function(acc,curr){
            return acc.concat(curr[0].split(',').map(function(el,_,cursplit){
                return [el, curr[1]/cursplit.length,curr[2]/cursplit.length];
            }));
        },[]);

但我不确定它是否更具可读性

var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
    var r = res.reduce(function(acc,curr){
        return acc.concat(curr[0].split(',').map(function(el,_,cursplit){
            return [el, curr[1]/cursplit.length,curr[2]/cursplit.length];
        }));
    },[]);

document.getElementById('d').innerHTML = r.join('<br>');
<div id="d"></div>

更新 另一种变异 res

for(var i=0,len=res.length;i<len;i++){
    var cur = res.shift();
    cur[0].split(',').forEach(function(el,_,cursplit){
            res.push([el, cur[1]/cursplit.length,cur[2]/cursplit.length]);
    });
}

var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
for(var i=0,len=res.length;i<len;i++){
    var cur = res.shift();
    cur[0].split(',').forEach(function(el,_,cursplit){
            res.push([el, cur[1]/cursplit.length,cur[2]/cursplit.length]);
    });
}

document.getElementById('d').innerHTML = res.join('<br>');
<div id="d"></div>

您可以使用 spliceres:

进行真正的就地处理
for (var i = 0; i < res.length; ) {
  var row = res[i];
  var keys = row[0].split(',')
  res.splice(i, 1); // Remove old element
  // Insert new elements at current position
  for (var j in keys)
    res.splice(i++, 0, [keys[j], row[1] / keys.length, row[2] / keys.length]);
}

结果:

[
 ["1", 33.333333333333336, 16.666666666666668],
 ["2", 33.333333333333336, 16.666666666666668],
 ["3", 33.333333333333336, 16.666666666666668],
 ["4", 37.5, 5],
 ["5", 37.5, 5],
 ["6", 20, 90]
]

编辑:

另一个避免拼接的技巧是扩展res的大小并从末尾开始填充它:

var n = res.length;

// Precalculate new length
var length = 0;
for (var i = 0; i < res.length; i++)
    length += res[i][0].split(',').length;

// Change length of array
res.length = length;

// Start filling from end to start
for (var i = n - 1, k = length - 1; i >= 0; i--) {
    var row = res[i];
    var keys = row[0].split(',');
    for (var j = keys.length - 1; j >= 0; j--)
        res[k--] = [keys[j], row[1] / keys.length, row[2] / keys.length];
}