RangeError: Maximum call stack size exceeded with array.push(...) - javascript

The simple code below produces RangeError: Maximum call stack size exceeded
const arr = []
for (let i = 0; i < 135000; i++) {
arr.push(i)
}
const arr2 = []
// something else here that changes arr2
arr2.push(...arr)
1) Why does this happen? (I am simply adding element to an array, why does it increase stack size ?)
2) How to fix this error ? (My goal is to create a shallow copy of arr into arr2)

The spread operator there pushes all elements in the original array into the stack, just like .apply:
const arr = [];
for (let i = 0; i < 10; i++) {
arr.push(i);
}
const arr2 = [];
// Something else here that changes arr2:
arr2.push(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Array.prototype.push.apply(arr2, arr);
console.log(arr2.join(', '));
So the amount of data you can handle in both cases is limited by the stack size:
const arr = [];
for (let i = 0; i < 135000; i++) {
arr.push(i);
}
const arr2 = [];
// Something else here that changes arr2:
arr2.push(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Array.prototype.push.apply(arr2, arr);
console.log(arr.length, arr2.length);
You could do this instead:
const arr = [];
for (let i = 0; i < 135000; i++) {
arr.push(i);
}
let arr2 = [];
// Something else here that changes arr2:
arr2.push(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
arr2 = [...arr2, ...arr];
console.log(arr.length, arr2.length);

When you use spread operator all items of the source array are stored in the stack as arguments list, so having a large number of items (~ > 100K) will cause the this stack size exceed.
The most simple work-around is to manually push all items one by one.
You can have a helper/utility function like this:
function largePush(src, dest){
const len = src.length
for(let i = 0; i < len; i++){
dest.push(src[i])
}
}
and use it like this:
const arr = []
for (let i = 0; i < 135000; i++) {
arr.push(i)
}
const arr2 = []
largePush(arr, arr2)

//I hope this will help you to make shallow copy of arr into arr2
let arr = []
for (let i = 0; i < 135000; i++) {
arr.push(i)
}
let arr2 = []
// something else here that changes arr2
arr2=arr
console.log(arr2[0],arr[0]);
//Both 0,0
arr[0]=100
console.log(arr[0],arr2[0])
//Both 100,100

Related

How to turn this solution from O(n^2) to O(n)?

I am having some problems turning this solution from O(n^2) to O(n). Can anyone kindly help? I am not able to think of any ways to make the time complexity O(n).
//MERGE SORTED ARRAY
/*arr1 = [0,3,4,31]
arr2 = [4,6,30]*/
const mergeSortedArrays = (arr1, arr2) => {
let arr = [];
let flag = true;
// MERGING ARRAYS
for (let i = 0; i < arr1.length; i++) {
arr.push(arr1[i]);//PUSHING ARRAY1 in arr
}
for (let i = 0; i < arr2.length; i++) {
arr.push(arr2[i]);//PUSING ARRAY2 in arr
}
//SORTING ARRAYS
while (flag) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = temp;
flag = true;
} else {
flag = false;
}
}
}
console.log(arr1);
console.log(arr2);
console.log(arr);//FINAL MERGED & SORTED ARRAY
// return arr;
}
mergeSortedArrays([0, 3, 4, 31], [4, 6, 30]);
Try visualising it. It is as if you had two sorted stacks of cards you wanted to sort. You can compare cards at the top of each stack, and put the smaller value on a third stack. And repeat until all cards are on the third sorted stack.
You can keep up two pointers, i and j, one for each array. This will emulate a stack.
The algorithm:
Repeat until the end of both arrays is reached:
if arr1[i] <= arr2[j]
push arr1[i] to the merged array and increment i
else
push arr2[j] to the merged array and increment j
And some javascript code:
let merged = [];
let i = 0;
let j = 0;
while(i < arr1.length || j < arr2.length){
if(j == arr2.length || (i < arr1.length && arr1[i] <= arr2[j])){
merged.push(arr1[i]);
i++;
} else{
merged.push(arr2[j]);
j++;
}
}
You can use two pointer method
(this solution is based on the assumption that the two lists will always be sorted):
let p1 = 0, p2 = 0;
let arr = [];
while (p1 < arr1.length && p2 < arr2.length) {
if (arr1[p1] < arr2[p2])
arr.push(arr1[p1++]);
else
arr.push(arr2[p2++]);
}
while (p1 < arr1.length)
arr.push(arr1[p1++]);
while (p2 < arr2.length)
arr.push(arr2[p2++]);
This code will run at the time complexity of O(N).
Updated answer based on comments from using Array#sort() to:
const mergeSortedArrays = (arr1, arr2) => {
const array = { arr1, arr2 }
const index = { a1: 0, a2: 0 }
const length = { a1: array.arr1.length, a2: array.arr2.length }
const merged = []
let current = 0
while (current < length.a1 + length.a2) {
const [a, i] =
!(index.a1 >= length.a1) &&
(index.a2 >= length.a2 || array.arr1[index.a1] < array.arr2[index.a2])
? ['arr1', 'a1']
: ['arr2', 'a2']
merged[current] = array[a][index[i]]
index[i]++
current++
}
return merged
}
const result = mergeSortedArrays([0, 3, 4, 31], [4, 6, 30])
console.log(result)

2D Array loop behaving strangely (FCC)

I'm doing a learning exercise and am trying to understand the following code. I thought I had a handle on arrays and loops, but this one has got me very confused.
The below code:
function zeroArray(m, n)
{
let newArray = [];
let row = [];
for (let i = 0; i < m; i++)
{
for (let j = 0; j < n; j++)
{
row.push(0);
}
newArray.push(row);
}
return newArray;
}
let matrix = zeroArray(3, 2);
console.log(matrix);
Returns
[ [ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ] ]
However I would have expected it to return
[ [ 0, 0, ],
[ 0, 0, 0, 0, ],
[ 0, 0, 0, 0, 0, 0 ] ]
Given that in each i loop, we are pushing (0) to row[] twice, before pushing row[] into newArray.
This isn't happening though, and in my VSCode debugger it looks as though in each i loop, every existing index of newArray is being updated with the latest version of the row[] array.
Why is this?
1) Start outer loop with i = 1 upto i <= m, so the loop count will be m
for (let i = 1; i <= m; i++) {
2) You should create a new row every time the inner loop start and push row into newArray after the inner loop ends
3) Set inner loop condition as j < n * i
for (let j = 0; j < n * i; j++) {
function zeroArray(m, n) {
let newArray = [];
// const row = [] // (-)
for (let i = 1; i <= m; i++) {
const row = []; // (+)
for (let j = 0; j < n * i; j++) { // (+)
row.push(0);
}
newArray.push(row);
}
return newArray;
}
let matrix = zeroArray(3, 2);
console.log(matrix);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
You need to make a copy of the array when pushing to newArray:
function zeroArray(m, n) {
let newArray = [];
let row = [];
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
row.push(0);
}
newArray.push(row.slice());
}
return newArray;
}
let matrix = zeroArray(3, 2);
console.log(JSON.stringify(matrix));
Matrix m x n should be m rows and n cols.
So for 3, 2 you expect
[
[0, 0],
[0, 0],
[0, 0],
]
Just declare row inside the first loop:
function zeroArray(m, n) {
const newArray = [];
for (let i = 0; i < m; i++) {
const row = [];
for (let j = 0; j < n; j++) {
row.push(0);
}
newArray.push(row);
}
return newArray;
}
let matrix = zeroArray(3, 2);
console.log(matrix);

I need to count the number of consecutive zeroes and update the new array with such count. each such block of zeroes has to be counted separately

I need to count consecutive blocks which are filled with zero and update the array result with each block separately like this [3,2,5]
This is my attempt, but it gives me the total number of zeros [10].
Also i need to return the Position of first Element of each Block in another array like this [2,6,11].
var A = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0];
var N = A.length;
function AvailConseblocks(A) {
var counter = 0;
var result = [];
var POS = [];
for (let i = 0; i < A.length; i++) {
if (A[i] === 0) {
counter++;
POS.push(i)
}
}
result.push(counter);
return result
}
console.log(AvailConseblocks(A));
let arr = [1,0,0,0,1,1,0,0,1,1,1,0,0,0,0,0]
let result =arr.join('').split(/[^0]/g).filter(e => e).map(e => e.length)
console.log(result)
This should work, not tested for edge cases.
var A = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0];
var N = A.length;
function AvailConseblocks(A) {
var counter = 0;
var result = [];
for (let i = 0; i < A.length; i++) {
if (A[i] === 0) {
counter++;
} else {
// if element is not zero and counter is not zero as well
// means we found 0 or 0's surrounded by non-zero elements
// we push the counter and re-intialize it to zero
if (counter !== 0) {
result.push(counter);
counter = 0;
}
}
}
// this is important if last element of the array was zero as well
if (counter !== 0) {
result.push(counter);
}
return result;
}
console.log(AvailConseblocks(A));
It can do the job done
const countNumbers = (count) => {
let arr = [];
for (let i = 0; i < count.length; i++) {
arr = arr.concat(count[i]);
}
let zero = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 0) zero++;
}
return zero;
};
console.log(countNumbers([2, 3, 44, 0, 0, 0, 00])); // ans : 4

Pushing entries into an array in a nested loop [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 3 years ago.
My code:
function zeroArray() {
let newArray = [];
let row = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 2; j++) {
row.push(0);
}
newArray.push(row);
}
return newArray
}
console.log(zeroArray())
From my perspective, its look like the result will be :
[[ 0, 0 ],[ 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0 ]]
but when the code run in the console it shows this, why is that?
[ [ 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0 ] ]
function zeroArray() {
let newArray = [];
let row = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 2; j++) {
row.push(0);
}
newArray.push(row); // <== Problematic line
}
return newArray;
}
The problem is when you push row array into newArray, it doesn't actually push the values into it; it pushes the pointer to that array, which means after updating row array, if you push it again, it will push the same value to newArray.
Posted the illustration for detailed explanation:
The solution is as some other people noted, re-creating the array each time instead of using the same variable. For example, the solution could be:
function zeroArray() {
const newArray = [];
for (let i = 0; i < 3; i++) {
const row = [];
for (let j = 0; j < 2; j++) {
row.push(0);
}
newArray.push(row); // <== Problematic line
}
return newArray;
}
Looks like an unexpected instance of mutating an object. In this case, you're pushing the same row multiple times, then updating it (resulting in that it updates the three instances of it that end up in newArray). If you instead use something like newArray.push(row.slice()), the output will be as you expect.

Dynamically create index in two dimensional array

Having some trouble with this script. It iterates through a two dimensional array and adds each corresponding index together. So basically arr[0][1] + arr[0][2] + arr[0][3] ... arr[1][1] + arr[1][2] + arr[1][3] ...etc.
This first one works fine. So my logic is ok. My problem here is that I can't create the indices dynamically. I don't think a push will work since I'm summing values here.
var cat_stats_week_radar = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0]];
for (var i = 0; i < cat_stats_week.length; i++) {
for (var j = 0; j < cat_stats_week[0].length; j++) {
cat_stats_week_radar[0][j] += +(cat_stats_week[i][j]);
}
}
This one doesn't work, I don't get an error, just a bunch of NaN values.
var cat_stats_week_radar = [[]];
for (var i = 0; i < cat_stats_week.length; i++) {
for (var j = 0; j < cat_stats_week[0].length; j++) {
cat_stats_week_radar[0][j] += +(cat_stats_week[i][j]);
}
}
Here are the arrays I'm working with.
Array to add:
var cat_stats_week = [
[0,0,0,0,0,0,0,1,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,1,0],
[0,0,0,0,0,0,0,0,0,0,0,0,1,0],
[0,0,1,0,0,0,0,0,0,0,0,0,0,0]
];
Resulting array:
var cat_stats_week_radar = [[0, 0, 1, 0, 0, 0, 2, 1, 0, 0, 0, 0, 2, 0]];
You need to initialize it with the right number of zeroes:
var cat_stats_week_radar = [[]];
for (var i = 0; i < cat_stats_week[0].length; i++) {
cat_stats_week_radar[0].push(0);
}
And with Underscore.js:
_.map(_.zip.apply(null, cat_stats_week), function(a) {
return _.reduce(a, function(a, b) {
return a + b
})
});

Categories

Resources