Why does function reassign 2Darray argument as sideeffect from calling the latter - javascript

When I run the third line alone and log test2darr it returns a 2D array filled with 6's in a 3x3 matrix
But when I run the fourth line and log test2darr again, it returns:
[4, 5, 4]
​
[5, 6, 5]​
[4, 5, 4]
(as well as for secondtest)
Though it should return the same array of 6's for test2darr and on assign the 2d array to secondtest
const n = 3;
const filler = new Array(n * n);
const test2darr = fill2DarrFromArr(filler.fill(6));
const secondtest = pileReduce(test2darr);
Here is my code for fill2DarrFromArr and pileReduce:
function pileReduce(_cells) {
_cells = fillEmpty(_cells);
for (let j = 0; j < _cells.length; j++) { //The Algorithm itself is not important
for (let i = 0; i < _cells.length; i++) { // But there might be some assignment problem that I missed
if (_cells[j][i] >= 4) {
_cells[j][i] = _cells[j][i] - 4;
if (j !== _cells.length - 1) _cells[j + 1][i]++;
if (j !== 0) _cells[j - 1][i]++;
if (i !== _cells.length - 1) _cells[j][i + 1]++;
if (i !== 0) _cells[j][i - 1]++;
}
}
}
return _cells;
}
function fill2DarrFromArr(_arr) {
let sideLength = Math.sqrt(_arr.length);
let out = create2DArr(sideLength, sideLength);
for (let j = 0; j < sideLength; j++) {
for (let i = 0; i < sideLength; i++) {
out[j][i] = _arr[j * sideLength + i];
}
}
return out;
}
function create2DArr(_n, _m) {
let _arr = new Array(_n);
for (let j = 0; j < _m; j++) {
_arr[j] = new Array(_m);
}
return _arr;
}
function fillEmpty(_arr) {
for (let j = 0; j < _arr.length; j++) {
for (let i = 0; i < _arr.length; i++) {
if (!_arr[j][i]) _arr[j][i] = 0;
}
}
return _arr;
}

Passing an array into a function doesn't create a copy of that array. Your functions are modifying the contents of the passed arrays, therefore they have side effects.

Related

using splice inside 2D Array in Javascript

I've created this 2D array, and I'm trying to delete the rows that are having 5 "ones" or more,
I tried it with splice (a.splice(j,1)) but it doesn't work . I think because when using this method it changes the whole quantity of rows and that's affects the for loops.
Is it because I don't use splice correctly or should I use different method ?
Thanks !
a = Array(7).fill(0).map(x => Array(10).fill(0))
for (let i = 0; i < 5; i++) {
a[1][i + 2] = 1;
a[4][i + 2] = 1;
a[5][i + 2] = 1;
}
console.log(a);
let count = 0;
for (let j = 0; j < 7; j++) {
for (let i = 0; i < 10; i++) {
if (a[j][i] == 1) {
count = count + 1;
}
}
if (count > 4) {
console.log("Line" + j);
// a.splice(j,1);
}
count = 0;
// a.splice(j,1);
}
Your splice is correct but you move forward through the array (j is incremented). To do this type of operation you need to move backward through the array (j is decremented) - this way the changing array indices don't intefere with your loop.
See the example below:
a = Array(7).fill(0).map(x => Array(10).fill(0))
for (let i=0; i<5; i++) {
a[1][i+2] = 1;
a[4][i+2] = 1;
a[5][i+2] = 1;
}
console.log("Original array");
console.log(a);
for (let j = a.length - 1; j > 0; j--) {
var count;
for (let i = 0; i < a[j].length; i++) {
if (a[j][i] === 1) {
count += 1
}
}
if (count > 4) {
a.splice(j, 1);
}
count = 0;
}
console.log("Filtered array");
console.log(a);

Why do I get an Uncaught TypeError: property 4 is undefined when looping through a 2d array?

So I am building Tetris. After creating an array, data, I am trying to implement gravity by checking
every string in an array if it's is "full" as well as being able the space below it being empty. However, it is giving me an error that suggests that something is undefined. The I tried a for loop and a for...of loop, as well as Googling it.Why do I get this error, and how can I fix it?
const editor = document.getElementById("edit");
var data = [];
function array(x, text) {
var y = [];
for (var i = 0; i < x - 1; i++) {
y.push(text);
}
return y;
}
for (var i = 0; i < 20; i++) {
data.push(array(10, "b"));
}
function draw() {
var j;
var i;
var dataOut = data;
for (i = 0; i < data.length; i++) {
for (j = 0; j < data[i].length; j++) {
if (data[i][j] == "a" && data[i + 1][j] == "b") {
if (i < data.length - 1) {
dataOut[i][j] = "b";
dataOut[i + 1][j] = "a";
}
}
}
}
data = dataOut;
console.log(data);
requestAnimationFrame(draw);
}
data[0][4] = "a";
requestAnimationFrame(draw);
with for-of-loop you iterate only objects/values of array and not indexes.
use only for-loop in order to use indexes
const editor = document.getElementById("edit");
var data = [];
function array(x, text) {
var y = [];
for (var i = 0; i < x - 1; i++) {
y.push(text);
}
return y;
}
for (var i = 0; i < 20; i++) {
data.push(array(10, "b"));
}
function draw() {
var dataOut = data;
for (let i = 0; i < data.length - 1; i++) { // logical error here
for (let j = 0; j < data.length; j++) {
if (data[i][j] == "a" && data[i + 1][j] == "b") {
if (i < data.length - 1) {
dataOut[i][j] = "b";
dataOut[i + 1][j] = "a";
}
}
}
}
data = dataOut;
console.log(data);
requestAnimationFrame(draw);
}
data[0][4] = "a";
requestAnimationFrame(draw);
A simple example of for-of-loop
const arr = ["aa","bb"]
for(let a of arr) console.log(a);
// will print
/*
aa
bb
*/
for(let a = 0; a < arr.length; a++) console.log(a);
// will print
/*
0
1
*/

Correct merge sort

So... If I input:
4 1 5 3
INSTEAD OF 1,3,4,5
I GET [ 4, 1, 5, 3 ]
Following is the code for merge sort but for the last comparison the program doesn't fetch updated (1,4) (3,5) value rather (4,1) (5,3) thus giving the wrong result.
var a = [4, 1, 5, 3];
q(a);
function q(a) {
var start = 0;
var n = a.length;
var length = parseInt(n / 2);
if (n < 2) {
return n;
}
var l = [], r = [];
for (i = 0; i < length; i++) {
l[i] = a[i]; //left array
}
for (i = 0, j = length; j < n; i++ , j++) {
r[i] = a[j]; //right array
}
q(l); //merge sort left array
q(r); //merge sort right array
comp(l, r);
}
function comp(l, r) {
var k = [], m = 0, i = 0, j = 0;
while (i < ((l.length)) && j < ((r.length))) {
if (l[i] < r[j]) {
k[m] = l[i];
i++;
m++
}
else {
k[m] = r[j];
j++;
m++
}
}
while (i != (l.length)) {
k[m] = l[i];
m++;
i++;
}
while (j != (r.length)) {
k[m] = r[j];
m++;
j++;
}
console.log(k); //for final output it is [ 4, 1, 5, 3 ] instead of [1,3,4,5]
}
You have a couple small problems. The main one is that you are returning the wrong thing from your edge condition:
if (n < 2) {
return n; // n is just a length; doesn't make sense to return it.
}
n is the length, you really want to return the small array here:
if (n < 2) {
return a; // return the array instead
}
Also, you need to pass the result of the recursive call to your comp function. Right now you're just returning the original lists with:
comp(l, r)
Something like this would work better:
let l_sort = q(l); //merge sort left array
let r_sort = q(r); //merge sort right array
return comp(l_sort, r_sort); // merge the arrays when recursion unwinds.
And you need to return things for recursion to work.
Put all together:
function q(a) {
var start = 0;
var n = a.length;
var length = parseInt(n / 2);
if (n < 2) {
return a;
}
var l = [],
r = [];
for (i = 0; i < length; i++) {
l[i] = a[i]; //left array
}
for (i = 0, j = length; j < n; i++, j++) {
r[i] = a[j]; //right array
}
let l_sort = q(l); //merge sort left array
let r_sort = q(r); //merge sort right array
return comp(l_sort, r_sort);
}
function comp(l, r) {
var k = [],
m = 0,
i = 0,
j = 0;
while (i < ((l.length)) && j < ((r.length))) {
if (l[i] < r[j]) {
k[m] = l[i];
i++;
m++
} else {
k[m] = r[j];
j++;
m++
}
}
while (i != (l.length)) {
k[m] = l[i];
m++;
i++;
}
while (j != (r.length)) {
k[m] = r[j];
m++;
j++;
}
return k
}
console.log(q([4, 1, 5, 3]).join(','));
console.log(q([5, 4, 3, 2, 1]).join(','));
console.log(q([2, 3]).join(','));
console.log(q([3, 2]).join(','));
console.log(q([1]).join(','));

Universal function for getting all unique pairs, trebles etc from an array in javascript

I am looking to create a function in javascript, which would allow me to pass a long array, together with one argument.
what I'm looking for is something like this:
var ar = [1,2,3,4];
var pairs = superAwesomeFunction(ar,2) //=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]];
var trebles = superAwesomeFunction(ar,3) //=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]
ideally, the function would have no limit on the folding argument.
I wrote a piece of code that looks like this, which is working fine, but it's not really useful as it isn't universal, and I would need a lot of such functions, which seems silly.
getAll2Folds: function (ar) {
var combinations = [],
numOdds = ar.length;
for (var i = 0; i < numOdds; i++) {
for (var j = i + 1; j < numOdds; j++) {
combinations.push([ar[i], ar[j]]);
}
}
return combinations;
},
getAll3Folds: function (ar) {
var combinations = [],
numOdds = ar.length;
for (var i = 0; i < numOdds; i++) {
for (var j = i + 1; j < numOdds; j++) {
for (var k = j + 1; k < numOdds; k++) {
combinations.push([ar[i], ar[j], ar[k]]);
}
}
}
return combinations;
};
},
... (not so great :|)
getAll8Folds: function (ar) {
var combinations = [],
numOdds = ar.length;
for (var i = 0; i < numOdds; i++) {
for (var j = i + 1; j < numOdds; j++) {
for (var k = j + 1; k < numOdds; k++) {
for (var l = k + 1; l < numOdds; l++) {
for (var m = l + 1; m < numOdds; m++) {
for (var n = m + 1; n < numOdds; n++) {
for (var o = n + 1; o < numOdds; o++) {
for (var p = o + 1; p < numOdds; p++) {
combinations.push([ar[i], ar[j], ar[k], ar[l], ar[m], ar[n], ar[o], ar[p]]);
}
}
}
}
}
}
}
}
return combinations;
}
I'm free to use underscore, jquery or whatever tool i want, but can't find an elegant solution, which would also be performant. ideas?
Thanks
Basically combine() takes an array with the values to combine and a size of the wanted combination results sets.
The inner function c() takes an array of previously made combinations and a start value as index of the original array for combination. The return is an array with all made combinations.
The first call is allways c([], 0), because of an empty result array and a start index of 0.
var arr = [1, 2, 3, 4, 5, 6, 7];
function combine(a, size) {
function c(part, start) {
var result = [], i, l, p;
for (i = start, l = arr.length; i < l; i++) {
// get a copy of part
p = part.slice(0);
// add the iterated element to p
p.push(a[i]);
// test if recursion can go on
if (p.length < size) {
// true: call c again and concat it to the result
result = result.concat(c(p, i + 1));
} else {
// false: push p to the result, stop recursion
result.push(p);
}
}
return result;
}
return c([], 0);
}
out(JSON.stringify(combine(arr, 2), null, 4), true);
out(JSON.stringify(combine(arr, 3), null, 4), true);
out(JSON.stringify(combine(arr, 4), null, 4), true);
out(JSON.stringify(combine(arr, 5), null, 4), true);
out(JSON.stringify(combine(arr, 6), null, 4), true);
// just for displaying the result
function out(s, pre) {
var descriptionNode = document.createElement('div');
descriptionNode.className = 'description';
if (pre) {
var preNode = document.createElement('pre');
preNode.innerHTML = s + '<br>';
descriptionNode.appendChild(preNode);
} else {
descriptionNode.innerHTML = s + '<br>';
}
document.getElementById('out').appendChild(descriptionNode);
}
<div id="out"></div>

How to program Pascal's Triangle in Javascript - confusion re Arrays

I'm having a little trouble with my attempt at this problem. Code Below:
function pasc(n){
var result = [[1]];
for (var row = 1; row < n; row++){
for (var col = 1; col <= row; col++){
result[row][col] = result[row - 1][col] + result[row - 1][col - 1];
}
}
return result;
}
pasc(10)
for (var i = 0; i < result.length; i++){
document.write(result[i]+"<br>");
}
It seems the problem hinges on assigning values to an array using an expression like myArray[1][1] = "foo"
I'm confused about this because I can do this: var myArray = []; myArray[4] = "foo" which seems to suggest that an element can be created at an arbitrary position in a 1 dimensional array, but not with 2 dimensions.
Any help with clearing up my misconceptions appreciated.
The Pascal's Triangle can be printed using recursion
Below is the code snippet that works recursively.
We have a recursive function pascalRecursive(n, a) that works up till the number of rows are printed. Each row is a element of the 2-D array ('a' in this case)
var numRows = 10,
triangle,
start,
stop;
// N is the no. of rows/tiers
// a is the 2-D array consisting of the row content
function pascalRecursive(n, a) {
if (n < 2) return a;
var prevRow = a[a.length-1];
var curRow = [1];
for (var i = 1; i < prevRow.length; i++) {
curRow[i] = prevRow[i] + prevRow[i-1];
}
curRow.push(1);
a.push(curRow);
return pascalRecursive(n-1, a); // Call the function recursively
}
var triangle = pascalRecursive(numRows, [[1]]);
for(var i = 0; i < triangle.length; i++)
console.log(triangle[i]+"\n");
JavaScript doesn't have two-dimensional arrays. What it does have is arrays that happen to contain other arrays. So, yes, you can assign a value to any arbitrary position in an array, and the array will magically make itself big enough, filling in any gaps with 'undefined'... but you can't assign a value to any position in a sub-array that you haven't explicitly created yet. You have to assign sub-arrays to the positions of the first array before you can assign values to the positions of the sub-arrays.
Replacing
for (var row = 1; row < n; row++){
for (var col = 1; col <= row; col++){
with
for (var row = 1; row < n; row++){
result[row] = [];
for (var col = 1; col <= row; col++){
should do it. Assuming all of your indexing logic is correct, anyway. You've got some problems there, too, since your initial array only contains a single value, so result[row][col] = result[row - 1][col] + result[row - 1][col - 1]; is accessing at least one cell that has never been defined.
Thanks Logan R. Kearsley. I have now solved it:
function pasc(n){
var result = [];
result[0] = [1];
result[1] = [1,1];
for (var row = 2; row < n; row++){
result[row] = [1];
for (var col = 1; col <= row -1; col++){
result[row][col] = result[row-1][col] + result[row-1][col-1];
result[row].push(1);
}
}
return result;
}
for (var i = 0; i < pasc(10).length; i++){
document.write(pasc(10)[i]+"<br>");
console.log(pasc(10)[i]+"<br>");
}
you can create Pascal's triangle using below code:
function pascal(n) {
var arr = [];
if (n == 1) {
arr[0] = [];
arr[0][0] = 1;
} else if (n == 2) {
arr[0] = [];
arr[0][0] = 1;
arr[1] = [];
arr[1][0] = 1;
arr[1][1] = 1;
} else if (n > 2) {
arr[0] = [];
arr[1] = [];
arr[0][0] = 1;
arr[1][0] = 1;
arr[1][1] = 1;
for (i = 2; i < n; i++) {
arr[i] = [];
arr[i][0] = 1;
for (j = 1; j < i; j++) {
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
arr[i][j] = 1;
}
}
console.log(arr);
for (i = 0; i < arr.length; i++) {
console.log(arr[i].join(' '))
}
}
function pascal(n) {
var arr = [];
if (n == 1) {
arr[0] = [];
arr[0][0] = 1;
} else if (n == 2) {
arr[0] = [];
arr[0][0] = 1;
arr[1] = [];
arr[1][0] = 1;
arr[1][1] = 1;
} else if (n > 2) {
arr[0] = [];
arr[1] = [];
arr[0][0] = 1;
arr[1][0] = 1;
arr[1][1] = 1;
for (i = 2; i < n; i++) {
arr[i] = [];
arr[i][0] = 1;
for (j = 1; j < i; j++) {
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
arr[i][j] = 1;
}
}
console.log(arr);
for (i = 0; i < arr.length; i++) {
console.log(arr[i].join(' '))
}
}
pascal(5)
This function will calculate Pascal's Triangle for "n" number of rows. It will create an object that holds "n" number of arrays, which are created as needed in the second/inner for loop.
function getPascalsTriangle(n) {
var arr = {};
for(var row = 0; row < n; row++) {
arr[row] = [];
for(var col = 0; col < row+1; col++) {
if(col === 0 || col === row) {
arr[row][col] = 1;
} else {
arr[row][col] = arr[row-1][col-1] + arr[row-1][col];
}
}
}
return arr;
}
console.log(getPascalsTriangle(5));
Floyd triangle
You can try the following code for a Floyd triangle
var prevNumber=1,i,depth=10;
for(i=0;i<depth;i++){
tempStr = "";j=0;
while(j<= i){
tempStr = tempStr + " " + prevNumber;
j++;
prevNumber++;
}
console.log(tempStr);
}
You can create arbitrary 2d arrays and store it in there and return the correct Pascal.
JavaScript does not have a special syntax for creating multidimensional arrays. A common workaround is to create an array of arrays in nested loops.
source
Here is my version of the solution
function pascal(input) {
var result = [[1], [1,1]];
if (input < 0) {
return [];
}
if (input === 0) {
return result[0];
}
for(var j = result.length-1; j < input; j++) {
var newArray = [];
var firstItem = result[j][0];
var lastItem = result[j][result[j].length -1];
newArray.push(firstItem);
for (var i =1; i <= j; i++) {
console.log(result[j][i-1], result[j][i]);
newArray.push(sum(result[j][i-1], result[j][i]));
}
newArray.push(lastItem);
result.push(newArray);
}
return result[input];
}
function sum(one, two) {
return one + two;
}
Here is the code i created for pascal triangle in javascript
'use strict'
let noOfCoinFlipped = 5
let probabiltyOfnoOfHead = 2
var dataStorer = [];
for(let i=0;i<=noOfCoinFlipped;i++){
dataStorer[i]=[];
for(let j=0;j<=i;j++){
if(i==0){
dataStorer[i][j] = 1;
}
else{
let param1 = (j==0)?0:dataStorer[i-1][j-1];
let param2 = dataStorer[i-1][j]?dataStorer[i-1][j]:0;
dataStorer[i][j] = param1+param2;
}
}
}
let totalPoints = dataStorer[noOfCoinFlipped].reduce((s,n)=>{return s+n;})
let successPoints = dataStorer[noOfCoinFlipped][probabiltyOfnoOfHead];
console.log(successPoints*100/totalPoints)
Here is the link as well
http://rextester.com/TZX59990
This is my solve:
function pascalTri(n){
let arr=[];
let c=0;
for(let i=1;i<=n;i++){
arr.push(1);
let len=arr.length;
if(i>1){
if(i>2){
for(let j=1;j<=(i-2);j++){
let idx=(len-(2*i)+j+2+c);
let val=arr[idx]+arr[idx+1];
arr.push(val);
}
c++;
}
arr.push(1);
}
}
return arr;
}
let pascalArr=pascalTri(7);
console.log(pascalArr);
here is the pattern for n = 3
#
##
###
here is js code to print this.
function staircase(n) {
for(var i=0 ; i<n ; i++) {
for(var j=n-1 ; j>i ; j--)
process.stdout.write(" ");
for(var k=0 ; k<=i; k++) {
process.stdout.write("#");
}
process.stdout.write("\n");
}
}
class PascalTriangle {
constructor(n) {
this.n = n;
}
factoriel(m) {
let result = 1;
if (m === 0) {
return 1;
}
while (m > 0) {
result *= m;
m--;
}
return result;
}
fill() {
let arr = [];
for (let i = 0; i < this.n; i++) {
arr.push([]);
}
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j <= i; j++) {
arr[i].push(this.factoriel(i) / (this.factoriel(j) * this.factoriel(i - j)));
}
}
return arr;
}
}
var m = prompt("enter number:");
var arrMain = new Array();
for (var i = 0; i < m; i++) {
arrMain[i] = [];
}
for (var i = 0; i < m; i++) {
if (i == 0) {
arrMain[i] = [1];
} else if (i == 1) {
(arrMain[i]) = [1, 1];
} else {
for (var j = 0; j <= i; j++) {
if (j == 0 || j == arrMain[i - 1].length) {
arrMain[i][j] = 1;
} else {
arrMain[i][j] = arrMain[i - 1][j] + arrMain[i - 1][j - 1];
}
}
}
document.write(arrMain[i] + "<br>");
}
This is my take on this problem by gaining access to the previous row.
const generate = numRows => {
const triangle = [[1]]
for (let i = 1; i < numRows; i++) {
// Previous row
const previous = triangle[i - 1]
// Current row
const current = new Array(i + 1).fill(1)
// Populate the current row with the previous
// row's values
for (let j = 1; j < i; j++) {
current[j] = previous[j - 1] + previous[j]
}
// Add to triangle result
triangle.push(current)
}
return triangle
}

Categories

Resources