2

I want to duplicate certain arrays in arrays using JavaScript, for example:

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 ] ]
*/

The arrays are really-really long, is it possible to do this in-place (res, without res2)?

3
  • you can try with reduce Commented Mar 26, 2015 at 11:45
  • 1
    @Grundy I don't think reduce qualifies as in-place Commented Mar 26, 2015 at 11:56
  • oh, @JuniorCompressor you right! Commented Mar 26, 2015 at 12:01

3 Answers 3

7

You can use splice for a true in-place processing of res:

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]);
}

Result:

[
 ["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]
]

EDIT:

Another trick to avoid splices is to extend the size of res and start filling it from the end to the beginning:

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];
}
Sign up to request clarification or add additional context in comments.

3 Comments

inserting to array(which is very long) is heavy, but yes, it seems like in-place.
@vp_arth I updated with a splice-less implementation
last one is beauty :3
2

You can use reduce function something like this

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];
            }));
        },[]);

but i'm not sure that it more readable

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>

UPDATE another variant with mutate 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>

Comments

2

You can get it with 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;
}, []);

But, I believe this still eat double memory :)

Another solution (with res2, but more economy):
It get source entities one-by-one, process it and gc allowed to clean memory...

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);
    });
}

1 Comment

This will eat double memory and it isn't inplace. You just assign res to another array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.