how to trace the for loop - javascript

function zeroArray(m, n) {
// Creates a 2-D array with m rows and n columns of zeroes
let newArray = [];
let row = [];
for (let i = 0; i < m; i++) {
// Adds the m-th row into newArray
for (let j = 0; j < n; j++) {
// Pushes n zeroes into the current row to create the columns
row.push(0);
}
// Pushes the current row, which now has n zeroes in it, to the array
newArray.push(row);
}
return newArray;
}
let matrix = zeroArray(3, 2);
console.log(JSON.stringify(matrix));
this code should print this
[[0,0], [0,0,0,0], [0,0,0,0,0,0]]
but instead its printing this
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
can someone trace the code?

I think this is about variable scope.you should declare row in for loop

When you push row, you are not pushing the contents of the row array, you are pushing a reference to the row array. As the row array changes through the loops, the values in the reference are updating.
If you slice() the row array when you push it into the new array, you will copy the values of the array, instead of a reference to it:
function zeroArray(m, n) {
// Creates a 2-D array with m rows and n columns of zeroes
let newArray = [];
let row = [];
for (let i = 0; i < m; i++) {
// Adds the m-th row into newArray
for (let j = 0; j < n; j++) {
// Pushes n zeroes into the current row to create the columns
row.push(0);
}
// Pushes the current row, which now has n zeroes in it, to the array
newArray.push(row.slice());
}
return newArray;
}
let matrix = zeroArray(3, 2);
console.log(matrix);
output:
[[0, 0], [0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
See:
Copy array by value

a solution...
function zeroArray(m, n)
{
let newArray = new Array(m)
, count = n
;
for (let i = 0; i < m; i++, count += n)
newArray[i] = new Array(count).fill(0)
;
return newArray
}
let matrix = zeroArray(3, 2);
console.log(JSON.stringify(matrix));

Related

Turning a multidimensional array into a single array

I'm doing the following codesignal:
Each of the rooms has a different cost, and some of them are free, but there's a rumour that all the free rooms are haunted! Since the CodeBots are quite superstitious, they refuse to stay in any of the free rooms, or any of the rooms below any of the free rooms.
Given matrix, a rectangular matrix of integers, where each value represents the cost of the room, your task is to return the total sum of all rooms that are suitable for the CodeBots (ie: add up all the values that don't appear below a 0).
Example
For
matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]]
the output should be
solution(matrix) = 9.
This is what I came up with, but it's not passing.
function solution(matrix) {
let rooms = []
for (let i = 0; i < matrix.length; i++) {
if (matrix[i] !== 0 || matrix[i-4] !== 0) {
rooms.push(i)
}
}
rooms.reduce((a, b) => a + b, 0)
}
I think it's not passing because its three small arrays in one large one. So is there a way to easily combine the three small arrays into one large one, then I can loop over it and run the conditional?
You don't need to convert to 1d array as it will be extra work, instead you solve it as follows:
you need to check whether the item above the one you are currently at is 0 or not. The item above any item in a 2d array is at index [i-1][j] where i is your current item. Make sure at i = 0 you directly add the item to the array to avoid getting index out of bounds exception.
This is my code:
let matrix = [[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]];
let sum = 0;
for(i = 0; i < matrix.length; i++) {
for(j = 0; j < matrix[i].length; j++) {
if(i === 0) {
sum += matrix[i][j];
continue;
}
if(i - 1 < 0) continue;
if(matrix[i - 1][j] !== 0) sum += matrix[i][j];
}
}
console.log(sum)
Loop over rows & columns, when 0 is found, sum 0 for that and further values in that column:
const matrix = [
[0, 1, 1, 2],
[0, 5, 0, 0],
[2, 0, 3, 3]
];
function solution (matrix) {
let skip = {}, sum = 0;
for (const a of matrix)
for (let i = 0; i < a.length; i++)
sum += skip[i] || (skip[i] = !a[i]) ? 0 : a[i];
return sum;
};
console.log(solution(matrix));

Remove particular array elements and push them to the back of the array [duplicate]

This question already has answers here:
Move zeroes to end of array in javascript - how to return nothing?
(21 answers)
Closed last year.
Trying to remove all 0's from an array and return them in the same array
So for example if I have this as an array
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]
I would get this:
let arrThree = [9,9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0,0]
This is what I wrote:
var remove = function (arr) {
let test = [];
for(let i = 0; i < arr.length; i++){
arr[i] === 0 ? test.push(arr.splice(i,1)) : false //if i is 0 then we want to push that into another array
}
arr.push(...test)
return [].concat(...arr)
}
When I run this function I get this
[
9, 9, 1, 2, 1, 1, 3,
1, 9, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0
]
Not sure where I am going wrong?
You need only two iterations, one for finding non zero values and another to put zeroes to the right side until end of the array. You need no array pushing or splicing.
const
move0 = array => {
let i = 0,
j = 0;
while (i < array.length) {
if (array[i]) array[j++] = array[i];
i++;
}
while (j < array.length) {
array[j] = '#'; // in reality it is zero
j++;
}
},
array = [9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0];
move0(array)
console.log(...array);
If you don't need to have any sorting on the non-zero elements, a rather efficient solution would be to swap the left-most 0 with the right-most non-zero element. Once your indices for tracking where you are on the left and right cross you'll know you're done.
function moveZeros(arr) {
let i = 0;
let j = arr.length - 1;
while(i < j) {
// Found a 0 to the left of a non-zero, swap.
if(arr[i] == 0 && arr[j] != 0) {
let tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
}
// Find a zero
if(arr[i] != 0) {
i++;
}
// Find a non-zero
if(arr[j] == 0) {
j--;
}
}
return arr;
}
console.log(moveZeros([1,2,0,3,0,0,0]));
console.log(moveZeros([9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]));
The issue with your code is you change the length of arr with arr.splice(i,1). This messes up the loop condition i < arr.length.
To fix your code, you can loop backwards through the array. So as the length of the array shortens, i is still valid.
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];
var remove = function(arr) {
let test = [];
for(let i = arr.length - 1; i >= 0; --i) {
if (arr[i] === 0) test.push(arr.splice(i, 1)[0]);
}
return arr.concat(test);
}
console.log(remove(arrThree));
There are a few other ways to do this. One is to use filter to create 2 arrays - one with no 0 and one with all 0 and join them:
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];
let remove = (arr) => arr.filter(i => i != 0).concat(arr.filter(i => i == 0));
console.log(remove(arrThree));

How to check if the input matrix is symmetric?

The code below takes in a matrix (MAT) and transposes the matrix, calls it array. The definition of the symmetrical matrix is that it should be a square matrix and the elements in the given matrix compared to the transposed one should be the same.
The given matrix below and transposed matrix should output false if checked for symmetry.
I did create an if statement at first to check whether MAT[j][i] and array[j][i] are the same but keep getting the wrong answer. It's not properly checking all the elements together. Could someone help with that?
Thanks!
const symmetricMatrix = function (MAT) {
let array = [];
for (let i = 0; i < MAT.length; i++) {
array.push([]);
for (let j = 0; j < MAT.length; j++) {
array[i].push(MAT[j][i]);
}
}
return array;
};
console.log(
symmetricMatrix(
(MAT = [
[1, 3, 1],
[-1, 1, 4],
[2, 1, 0],
])
)
);
First you can create a copy of matrix and then transpose it and then check if it has same element at that index.
const symmetricMatrix = function (mat) {
const copy = Array.from(mat, (_) => []);
for (let i = 0; i < mat.length; i++)
for (let j = 0; j < mat.length; j++)
copy[i][j] = mat[j][i];
for (let i = 0; i < mat.length; i++)
for (let j = 0; j < mat.length; j++)
if (copy[i][j] != mat[i][j]) return false;
return true;
};
const matrix = [
[1, 3, 1],
[-1, 1, 4],
[2, 1, 0],
];
const matrix2 = [
[1, -1, 2],
[-1, 1, 1],
[2, 1, 0],
];
console.log(symmetricMatrix(matrix));
console.log(symmetricMatrix(matrix2));

For loops seems to run double than what is expected

I'm having issues with leetcode algo question 1252. I'm not sure why but my for loop seems to run twice. The question is:
"Given n and m which are the dimensions of a matrix initialized by zeros and given an array indices where indices[i] = [ri, ci]. For each pair of [ri, ci] you have to increment all cells in row ri and column ci by 1.
Return the number of cells with odd values in the matrix after applying the increment to all indices."
var oddCells = function(n, m, indices) {
let matrix = [];
let array = Array(m).fill(0);
let k = 0;
while (k < n) {
matrix.push(array);
k++;
}
for (let i = 0; i < indices.length; i++) {
const row = indices[i][0];
const col = indices[i][1];
for (let j = 0; j < n; j++) {
matrix[j][col]++;
}
for (let i = 0; i < m; i++) {
matrix[row][i]++;
}
}
return matrix.flat().filter(number => number % 2 !== 0).length;
}
console.log(oddCells(2, 3, [
[0, 1],
[1, 1]
]));
The specific input I am testing is n = 2, m = 3, indices = [[0,1],[1,1]].
I've tried to follow my code manually but I can't figure out why the two inner for loops are iterating over the nested arrays twice rather than each one once. After the first loop[ the matrix is supposed to be [[1, 2, 1], [0, 1, 0]] but instead I end up with [[1, 3, 1], [1, 3, 1]].
This is a basic problem of reusing mutable reference values.
You are repeatedly pushing the same array to the matrix, so when you modify any value in that array, you are modifying multiple areas of the matrix.
So use separate arrays:
var oddCells = function(n, m, indices) {
let matrix = [];
let k = 0;
while (k < n) {
matrix.push(Array(m).fill(0));
k++;
}
for (let i = 0; i < indices.length; i++) {
const row = indices[i][0];
const col = indices[i][1];
for (let ri = 0; ri < n; ri++) {
matrix[ri][col]++;
}
for (let ci = 0; ci < m; ci++) {
matrix[row][ci]++;
}
}
return matrix.flat().filter(number => number % 2 !== 0).length;
}
console.log(oddCells(2, 3, [
[0, 1],
[1, 1]
]));

Declare an empty two-dimensional array in Javascript?

I want to create a two dimensional array in Javascript where I'm going to store coordinates (x,y). I don't know yet how many pairs of coordinates I will have because they will be dynamically generated by user input.
Example of pre-defined 2d array:
var Arr=[[1,2],[3,4],[5,6]];
I guess I can use the PUSH method to add a new record at the end of the array.
How do I declare an empty two dimensional array so that when I use my first Arr.push() it will be added to the index 0, and every next record written by push will take the next index?
This is probably very easy to do, I'm just a newbie with JS, and I would appreciate if someone could write a short working code snippet that I could examine. Thanks
You can just declare a regular array like so:
var arry = [];
Then when you have a pair of values to add to the array, all you need to do is:
arry.push([value_1, value2]);
And yes, the first time you call arry.push, the pair of values will be placed at index 0.
From the nodejs repl:
> var arry = [];
undefined
> arry.push([1,2]);
1
> arry
[ [ 1, 2 ] ]
> arry.push([2,3]);
2
> arry
[ [ 1, 2 ], [ 2, 3 ] ]
Of course, since javascript is dynamically typed, there will be no type checker enforcing that the array remains 2 dimensional. You will have to make sure to only add pairs of coordinates and not do the following:
> arry.push(100);
3
> arry
[ [ 1, 2 ],
[ 2, 3 ],
100 ]
If you want to initialize along with the creation, you can use fill and map.
const matrix = new Array(5).fill(0).map(() => new Array(4).fill(0));
5 is the number of rows and 4 is the number of columns.
ES6
Matrix m with size 3 rows and 5 columns (remove .fill(0) to not init by zero)
[...Array(3)].map(_=>Array(5).fill(0))
let Array2D = (r,c) => [...Array(r)].map(_=>Array(c).fill(0));
let m = Array2D(3,5);
m[1][0] = 2; // second row, first column
m[2][4] = 8; // last row, last column
// print formated array
console.log(JSON.stringify(m)
.replace(/(\[\[)(.*)(\]\])/g,'[\n [$2]\n]').replace(/],/g,'],\n ')
);
If you want to be able access the matrix like so:
matrix[i][j]
I find it the most convenient to init it in a loop.
var matrix = [],
cols = 3;
//init the grid matrix
for ( var i = 0; i < cols; i++ ) {
matrix[i] = [];
}
This will give you
[ [], [], [] ]
so
matrix[0][0]
matrix[1][0]
returns undefined and not the error "Uncaught TypeError: Cannot set property '0' of undefined".
You can nest one array within another using the shorthand syntax:
var twoDee = [[]];
You can try something like this:-
var arr = new Array([]);
Push data:
arr[0][0] = 'abc xyz';
An empty array is defined by omitting values, like so:
v=[[],[]]
a=[]
b=[1,2]
a.push(b)
b==a[0]
You can fill an array with arrays using a function:
var arr = [];
var rows = 11;
var columns = 12;
fill2DimensionsArray(arr, rows, columns);
function fill2DimensionsArray(arr, rows, columns){
for (var i = 0; i < rows; i++) {
arr.push([0])
for (var j = 0; j < columns; j++) {
arr[i][j] = 0;
}
}
}
The result is:
Array(11)
0:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
7:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
8:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9:(12) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
10:(12)[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
One Liner
let m = 3 // rows
let n = 3 // columns
let array2D = Array(m).fill().map(entry => Array(n))
This implementation creates a unique subarray for each entry. So setting array2D[0][1] = 'm' does not set each entry's [1] index to 'm'
I know this is an old thread but I'd like to suggest using an array of objects rather than an array of arrays. I think it make the code simpler to understand and update.
// Use meaningful variable names like 'points',
// anything better than a bad pirate joke, 'arr'!
var points = [];
// Create an object literal, then add it to the array
var point = {x: 0, y: 0};
points.push(point);
// Create and add the object to the array in 1 line
points.push({x:5, y:5});
// Create the object from local variables
var x = 10;
var y = 8;
points.push({x, y});
// Ask the user for a point too
var response = prompt("Please enter a coordinate point. Example: 3,8");
var coords = response.split(",").map(Number);
points.push({x: coords[0], y: coords[1]});
// Show the results
var canvas = document.getElementById('graph');
var painter = canvas.getContext("2d");
var width = canvas.width, height = canvas.height;
var scale = 10, radius = 3.5, deg0 = 0, deg360 = 2 * Math.PI;
painter.beginPath();
for (var point of points) {
var x = point.x * scale + scale;
var y = height - point.y * scale - scale;
painter.moveTo(x + radius, y);
painter.arc(x, y, radius, deg0, deg360);
painter.fillText(`${point.x}, ${point.y}`, x + radius + 1, y + radius + 1);
}
painter.stroke();
<canvas id="graph" width="150" height="150" style="border: 1px solid red;"></canvas>
This one should work:
const arr = new Array(5).fill().map(_ => new Array(5).fill(0)) // ✅
You may ask why did I use map instead of:
const badArr = new Array(5).fill(new Array(5).fill(0)) // ❌
The problem with the example above is that it adds references to the array that was passed into the fill method:
While this one works fine:
const grid = Array.from(Array(3), e => Array(4));
Array.from(arrayLike, mapfn)
mapfn is called, being passed the value undefined, returning new Array(4).
An iterator is created and the next value is repeatedly called. The value returned from next, next().value is undefined. This value, undefined, is then passed to the newly-created array's iterator. Each iteration's value is undefined, which you can see if you log it.
var grid2 = Array.from(Array(3), e => {
console.log(e); // undefined
return Array(4); // a new Array.
});
ES6
const rows = 2;
const columns = 3;
const matrix = [...Array(rows)].map(() => [...Array(columns)].fill(0));
console.log(matrix);
Create an object and push that object into an array
var jSONdataHolder = function(country, lat, lon) {
this.country = country;
this.lat = lat;
this.lon = lon;
}
var jSONholderArr = [];
jSONholderArr.push(new jSONdataHolder("Sweden", "60", "17"));
jSONholderArr.push(new jSONdataHolder("Portugal", "38", "9"));
jSONholderArr.push(new jSONdataHolder("Brazil", "23", "-46"));
var nObj = jSONholderArr.length;
for (var i = 0; i < nObj; i++) {
console.log(jSONholderArr[i].country + "; " + jSONholderArr[i].lat + "; " +
jSONholderArr[i].lon);
}
var arr = [];
var rows = 3;
var columns = 2;
for (var i = 0; i < rows; i++) {
arr.push([]); // creates arrays in arr
}
console.log('elements of arr are arrays:');
console.log(arr);
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
arr[i][j] = null; // empty 2D array: it doesn't make much sense to do this
}
}
console.log();
console.log('empty 2D array:');
console.log(arr);
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
arr[i][j] = columns * i + j + 1;
}
}
console.log();
console.log('2D array filled with values:');
console.log(arr);
The most simple way to create an empty matrix is just define it as an empty array:
// Empty data structure
const matrix = []
However, we want to represent something similar to a grid with n and m parameters know ahead then we can use this instead.
// n x m data structure
const createGrid = (n, m) => [...Array(n)].map(() => [...Array(m)].fill(0))
const grid = createGrid(3, 5)
Here is a simple snippet showing how to use them.
const createGrid = (n, m) => [...Array(n)].map(() => [...Array(m)].fill(0))
const toString = m => JSON.stringify(m)
.replace(/(\[\[)(.*)(]])/g, '[\n [$2]\n]')
.replace(/],/g, '],\n ')
// Empty data structure
const matrix = []
console.log(toString(matrix))
matrix.push([1,2,3])
matrix.push([4,5,6])
matrix.push([7,8,9])
console.log(toString(matrix))
// n x m data structure
const grid = createGrid(3, 5)
console.log(toString(grid))
No need to do so much of trouble! Its simple
This will create 2 * 3 matrix of string.
var array=[];
var x = 2, y = 3;
var s = 'abcdefg';
for(var i = 0; i<x; i++){
array[i]=new Array();
for(var j = 0; j<y; j++){
array[i].push(s.charAt(counter++));
}
}
If we don’t use ES2015 and don’t have fill(), just use .apply()
See https://stackoverflow.com/a/47041157/1851492
let Array2D = (r, c, fill) => Array.apply(null, new Array(r))
.map(function() {
return Array.apply(null, new Array(c))
.map(function() {return fill})
})
console.log(JSON.stringify(Array2D(3,4,0)));
console.log(JSON.stringify(Array2D(4,5,1)));
We usually know the number of columns but maybe not rows (records). Here is an example of my solution making use of much of the above here. (For those here more experienced in JS than me - pretty much everone - any code improvement suggestions welcome)
var a_cols = [null,null,null,null,null,null,null,null,null];
var a_rxc = [[a_cols]];
// just checking var arr = a_rxc.length ; //Array.isArray(a_rxc);
// alert ("a_rxc length=" + arr) ; Returned 1
/* Quick test of array to check can assign new rows to a_rxc.
i can be treated as the rows dimension and j the columns*/
for (i=0; i<3; i++) {
for (j=0; j<9; j++) {
a_rxc[i][j] = i*j;
alert ("i=" + i + "j=" + j + " " + a_rxc[i][j] );
}
if (i+1<3) { a_rxc[i+1] = [[a_cols]]; }
}
And if passing this array to the sever the ajax that works for me is
$.post("../ajax/myservercode.php",
{
jqArrArg1 : a_onedimarray,
jqArrArg2 : a_rxc
},
function(){ },"text" )
.done(function(srvresp,status) { $("#id_PageContainer").html(srvresp);} )
.fail(function(jqXHR,status) { alert("jqXHR AJAX error " + jqXHR + ">>" + status );} );
What's wrong with
var arr2 = new Array(10,20);
arr2[0,0] = 5;
arr2[0,1] = 2
console.log("sum is " + (arr2[0,0] + arr2[0,1]))
should read out "sum is 7"
const dp=new Array(3).fill(new Array(3).fill(-1))
It will create below array:
[ [ -1, -1, -1 ], [ -1, -1, -1 ], [ -1, -1, -1 ] ]
You can nest a new array as you fill the first one:
let ROWS = 2,
COLS = 6;
let arr = new Array(ROWS).fill(new Array(COLS).fill(-1));
Output:
arr =
[
[-1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1]
]
If you're confused, lets break this down with declaring/filling 1 array:
Make a new array size d, filled with any initial value
let arr1d = new Array(d).fill(<whatever_fill_val>);
Now, instead of filling your first array with a int/string/etc, you can fill it with ANOTHER array, as you fill the nested one!
let arr = new Array(d).fill(new Array(n).fill(-1));
// for 3 x 5 array
new Array(3).fill(new Array(5).fill(0))

Categories

Resources