Storing instances of an array using the slice method in javascript - javascript

I have an array list I loop over and modify it each time. I want to store all instances of my list array in an other array I named allLists, and to do so, I'm using the slice method.
It seems to work in the simple example below:
let list=[1,2,3,4];
let allList = [];
allList.push(list.slice());
list[2]=6;
allList.push(list.slice());
console.log(allList);// returns [1,2,3,4] [1,2,6,4]
But it doesn't work in the following code. Instead, allLists is filled with the last instance of the list array.
let list = Array.from({
length: 9
}, () => Array.from({
length: 9
}, () => [1, 2, 3, 4, 5, 6, 7, 8, 9]));
let allLists = [list.slice()];
let indexList = [];
let lengthList = [];
let key = true;
function handleNewIndex(list) {
let newIndex = [0, 0];
let maxLength = 9;
for (let i = 0; i < list.length; i++) {
for (let j = 0; j < list.length; j++) {
if (list[i][j].length < maxLength && list[i][j].length > 0) {
maxLength = list[i][j].length;
newIndex = [i, j];
}
}
}
return newIndex;
}
function isSudokuValid(list) {
for (let i = 0; i < list.length; i++) {
for (let j = 0; j < list.length; j++) {
if (list[i][j].length === 0) {
return false;
}
}
}
return true;
}
function handleWrongSudoku(allLists, indexList, lengthList) {
let counter = 1;
while (lengthList[lengthList.length - counter] <= 1) {
counter = counter + 1;
allLists.pop();
indexList.pop();
}
let wrongList = allLists.pop();
list = allLists.pop();
indexLine = indexList[indexList.length - 1][0];
indexColumn = indexList[indexList.length - 1][1];
let wrongNumber = wrongList[indexLine][indexColumn];
for (let i = 0; i < list[indexLine][indexColumn].length; i++) {
if (list[indexLine][indexColumn][i] != wrongNumber) {
list[indexLine][indexColumn] = list[indexLine][indexColumn][i];
}
}
allLists.push(list.slice());
indexLine = handleNewIndex(list)[0];
indexColumn = handleNewIndex(list)[1];
}
function generateSudoku() {
let indexLine = Math.floor(Math.random() * 9);
let indexColumn = Math.floor(Math.random() * 9);
let counter = 0;
while (counter < 81) {
indexList.push([indexLine, indexColumn]);
let bigSquareIndex = 3 * Math.floor(indexLine / 3) + Math.floor(indexColumn / 3);
lengthList.push(list[indexLine][indexColumn].length);
list[indexLine][indexColumn] = list[indexLine][indexColumn][Math.floor(Math.random() * list[indexLine][indexColumn].length)];
counter = counter + 1;
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
if (3 * Math.floor(i / 3) + Math.floor(j / 3) === bigSquareIndex) {
let k = 0;
let n = list[i][j].length;
while (list[i][j][k] != list[indexLine][indexColumn] && k < n) {
k = k + 1;
}
if (k < n) {
list[i][j].splice(k, 1);
}
} else if (i === indexLine || j === indexColumn) {
let k = 0;
let n = list[i][j].length;
while (list[i][j][k] != list[indexLine][indexColumn] && k < n) {
k = k + 1;
}
if (k < n) {
list[i][j].splice(k, 1);
}
}
}
}
allLists.push(list.slice());
key = isSudokuValid(list);
if (key === false) { //ignore this scenario, not done yet, assume key = true at all time
console.log(key, lengthList, indexList, allLists);
handleWrongSudoku(allLists, indexList, lengthList);
key = true;
//return;
} else {
indexLine = handleNewIndex(list)[0];
indexColumn = handleNewIndex(list)[1];
}
}
}
generateSudoku();
console.log(allLists); // returns 81 times the same 9x9 array instead of the 81 different instances of the list array
I don't know what I'm doing wrong here.

Thanks for the hint Code Maniac.
I used the JSON method instead to create a deep copy and it's working fine now.
allLists.push(JSON.parse(JSON.stringify(list)));
This post explains the difference between shallow and deep copy:
https://www.freecodecamp.org/news/how-to-clone-an-array-in-javascript-1d3183468f6a/

Related

how can I better run my code in javascript?

The exercise is as follows, given an array with multiple arrays inside, return the sum of the product subtraction with the LMC. I managed to create the code, but is passing 12000ms of response and wanted to optimize my code, I still have difficulty with it, can you help me? Follow the code below.
The expected result is 840.
let pairs = [[15,18], [4,5], [12,60]];
function sumDifferencesBetweenProductsAndLCMs (pairs)
{
let product = [];
let prodResult = 1;
let LMC = [];
let result = 0;
// take a product
for(let i = 0; i < pairs.length;i++)
{
for(let j = 0; j < pairs[i].length;j++)
{
prodResult *= pairs[i][j]
}
product.push(prodResult);
if(prodResult != 0)
{
prodResult = 1
}
}
// take a LMC
for(let i = 0; i < pairs.length;i++)
{
let m = pairs[i][0];
let n = pairs[i][1];
let a = pairs[i][0];
let b = pairs[i][1];
let mmc = 0;
let r = 0
do
{
r = m%n;
m=n;
n=r;
} while (r != 0);
mmc = (a * b)/m
LMC.push(mmc)
}
for(let i = 0; i < product.length; i++){
result += product[i]-LMC[i]
}
return result
}
console.log(sumDifferencesBetweenProductsAndLCMs(pairs));
You can do all calculation in single loop only which will reduce your run time complexity.
let pairs = [[15,18], [4,5], [12,60]];
function sumDifferencesBetweenProductsAndLCMs (pairs) {
let result = 0;
// take a product
for(let i = 0; i < pairs.length;i++) {
let prodResult = 1;
for(let j = 0; j < pairs[i].length;j++) {
prodResult *= pairs[i][j]
}
const lcmResult = lcm(pairs[i][0], pairs[i][1]);
result += prodResult - lcmResult;
}
return result
}
function lcm(a, b) {
return (a / gcd(a, b)) * b;
}
function gcd(a, b) {
if (a === 0) {
return b;
}
return gcd(b % a, a);
}
console.log(sumDifferencesBetweenProductsAndLCMs(pairs));
.as-console-wrapper {
top: 0;
}

I got a "TypeError: Cannot read property 'length' of undefined" error on my Javascript project I got following a tutorial. How do I fix the error?

I am following the Nature of Code tutorial by Code Train and when I tested the code I got the TypeError. It pointed to function FromArray, line 19. I am trying to follow his coding challenge on teaching the neural network xor, where he visualizes the xor problem. The code I have so far should produce a flicking black and white screen. Here is a specific error message I got:
at Function.fromArray (matrix.js:19)
at NeuralNetwork.train (nn.js:61)
at draw (sketch.js:44)
at e.d.redraw (p5.min.js:33)
at e.<anonymous> (p5.min.js:32)
at e.<anonymous> (p5.min.js:32)
at new e (p5.min.js:32)
at e (p5.min.js:32).
I tried rewatching some of the videos to see if I missed something and I even checked with his code on GitHub but I still get that error. I tried searching for what to do with TypeError but most answers I found on forums.
Please help. Also, his tutorial series is really good.
//This is my code for the matrix math (Matrix.js):
// let m = new Matrix(3,2);
class Matrix {
constructor(rows, cols) {
this.rows = rows;
this.cols = cols;
this.data = [];
for (let i = 0; i < this.rows; i++) {
this.data[i] = [];
for (let j = 0; j < this.cols; j++) {
this.data[i][j] = 0;
}
}
}
static fromArray(arr) {
let m = new Matrix(arr.length, 1);
for (let i = 0; i < arr.length; i++) {
m.data[i][0] = arr[i];
}
return m;
}
static subtract(a, b) {
// Return a new Matrix a-b
let result = new Matrix(a.rows, a.cols);
for (let i = 0; i < result.rows; i++) {
for (let j = 0; j < result.cols; j++) {
result.data[i][j] = a.data[i][j] - b.data[i][j];
}
}
return result;
}
toArray() {
let arr = [];
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
arr.push(this.data[i][j]);
}
}
return arr;
}
randomize() {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.data[i][j] = Math.random() * 2 - 1;
}
}
}
add(n) {
if (n instanceof Matrix) {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.data[i][j] += n.data[i][j];
}
}
} else {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.data[i][j] += n;
}
}
}
}
static transpose(matrix) {
let result = new Matrix(matrix.cols, matrix.rows);
for (let i = 0; i < matrix.rows; i++) {
for (let j = 0; j < matrix.cols; j++) {
result.data[j][i] = matrix.data[i][j];
}
}
return result;
}
static multiply(a, b) {
// Matrix product
if (a.cols !== b.rows) {
console.log('Columns of A must match rows of B.')
return undefined;
}
let result = new Matrix(a.rows, b.cols);
for (let i = 0; i < result.rows; i++) {
for (let j = 0; j < result.cols; j++) {
// Dot product of values in col
let sum = 0;
for (let k = 0; k < a.cols; k++) {
sum += a.data[i][k] * b.data[k][j];
}
result.data[i][j] = sum;
}
}
return result;
}
multiply(n) {
if (n instanceof Matrix) {
// hadamard product
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.data[i][j] *= n.data[i][j];
}
}
} else {
// Scalar product
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.data[i][j] *= n;
}
}
}
}
map(func) {
// Apply a function to every element of matrix
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
let val = this.data[i][j];
this.data[i][j] = func(val);
}
}
}
static map(matrix, func) {
let result = new Matrix(matrix.rows, matrix.cols);
// Apply a function to every element of matrix
for (let i = 0; i < matrix.rows; i++) {
for (let j = 0; j < matrix.cols; j++) {
let val = matrix.data[i][j];
result.data[i][j] = func(val);
}
}
return result;
}
print() {
console.table(this.data);
}
}
if (typeof module !== 'undefined') {
module.exports = Matrix;
}
//This the code that trains the neural network:
function sigmoid(x) {
return 1 / (1 + Math.exp(-x));
}
function dsigmoid(y) {
// return sigmoid(x) * (1 - sigmoid(x));
return y * (1 - y);
}
class NeuralNetwork {
constructor(input_nodes, hidden_nodes, output_nodes) {
this.input_nodes = input_nodes;
this.hidden_nodes = hidden_nodes;
this.output_nodes = output_nodes;
this.weights_ih = new Matrix(this.hidden_nodes, this.input_nodes);
this.weights_ho = new Matrix(this.output_nodes, this.hidden_nodes);
this.weights_ih.randomize();
this.weights_ho.randomize();
this.bias_h = new Matrix(this.hidden_nodes, 1);
this.bias_o = new Matrix(this.output_nodes, 1);
this.bias_h.randomize();
this.bias_o.randomize();
this.learning_rate = 0.1;
}
feedforward(input_array) {
// Generating the Hidden Outputs
let inputs = Matrix.fromArray(input_array);
let hidden = Matrix.multiply(this.weights_ih, inputs);
hidden.add(this.bias_h);
// activation function!
hidden.map(sigmoid);
// Generating the output's output!
let output = Matrix.multiply(this.weights_ho, hidden);
output.add(this.bias_o);
output.map(sigmoid);
// Sending back to the caller!
return output.toArray();
}
train(input_array, target_array) {
// Generating the Hidden Outputs
let inputs = Matrix.fromArray(input_array);
let hidden = Matrix.multiply(this.weights_ih, inputs);
hidden.add(this.bias_h);
// activation function!
hidden.map(sigmoid);
// Generating the output's output!
let outputs = Matrix.multiply(this.weights_ho, hidden);
outputs.add(this.bias_o);
outputs.map(sigmoid);
// Convert array to matrix object
let targets = Matrix.fromArray(target_array);
// Calculate the error
// ERROR = TARGETS - OUTPUTS
let output_errors = Matrix.subtract(targets, outputs);
// let gradient = outputs * (1 - outputs);
// Calculate gradient
let gradients = Matrix.map(outputs, dsigmoid);
gradients.multiply(output_errors);
gradients.multiply(this.learning_rate);
// Calculate deltas
let hidden_T = Matrix.transpose(hidden);
let weight_ho_deltas = Matrix.multiply(gradients, hidden_T);
// Adjust the weights by deltas
this.weights_ho.add(weight_ho_deltas);
// Adjust the bias by its deltas (which is just the gradients)
this.bias_o.add(gradients);
// Calculate the hidden layer errors
let who_t = Matrix.transpose(this.weights_ho);
let hidden_errors = Matrix.multiply(who_t, output_errors);
// Calculate hidden gradient
let hidden_gradient = Matrix.map(hidden, dsigmoid);
hidden_gradient.multiply(hidden_errors);
hidden_gradient.multiply(this.learning_rate);
// Calcuate input->hidden deltas
let inputs_T = Matrix.transpose(inputs);
let weight_ih_deltas = Matrix.multiply(hidden_gradient, inputs_T);
this.weights_ih.add(weight_ih_deltas);
// Adjust the bias by its deltas (which is just the gradients)
this.bias_h.add(hidden_gradient);
// outputs.print();
// targets.print();
// error.print();
}
}
//And this does the sketch and outputs the results:
let nn;
//Test Data
let training_data = [
{
inputs: [0,1],
targets: [1]
},
{
inputs: [1,0],
targets: [1]
},
{
inputs: [0,0],
targets: [0]
},
{
inputs: [1,1],
targets: [0]
},
];
function setup() {
//Test Data
// for (let i = 0; i < 50000; i++) {
// let data = random(training_data);
// nn.train(data.inputs, data.targets);
// }
// console.log(nn.feedforward([1,0]));
// console.log(nn.feedforward([0,1]));
// console.log(nn.feedforward([1,1]));
// console.log(nn.feedforward([0,0]));
createCanvas(400, 400);
nn = new NeuralNetwork(2, 2, 1);
}
function draw() {
background(0)
for (let i = 0; i < 1000; i++) {
let data = random(training_data);
nn.train(data.inputs, data.outputs);
}
let resolution = 10;
let cols = width / resolution;
let rows = height / resolution;
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
fill(random(255));
rect(i*resolution,j*resolution,resolution, resolution)
}
}
}

Where has my logic gone wrong in my attempt to implement a sudoku solver in Javascript?

const N = 4;
const fourbyfour = [
[1, 0, 0, 4],
[3, 4, 1, 2],
[2, 1, 4, 3],
[4, 3, 2, 1],
];
function solve(board) {
for (let i = 0; i < N; i++) {
for (let j = 0; j < N; j++) {
if (board[i][j] === 0) {
for (let k = 1; k < N + 1; k++) {
board[i][j] = k;
if (isValidBoard(board)) {
if (isSolved(board)) return board;
else solve(board);
}
}
}
}
}
return;
}
function isSolved(board) {
let cells = [];
for (let row of board) {
cells.push(...row);
}
return !cells.includes(0);
}
function isValidBoard(board) {
// Check rows are valid
for (let i = 0; i < N; i++) {
const row = board[i].filter((cell) => cell !== 0);
if (new Set(row).size !== row.length) {
return false;
}
}
// Check columns are valid
for (let i = 0; i < N; i++) {
let column = [];
for (let j = 0; j < N; j++) {
if (board[j][i] !== 0) column.push(board[j][i]);
}
if (new Set(column).size !== column.length) {
return false;
}
}
const root = Math.sqrt(N);
// Check each grid
for (let i = 0; i < N; i += root) {
for (let j = 0; j < N; j += root) {
const square = [];
for (let k = i; k < i + root; k++) {
for (let l = j; l < j + root; l++) {
if (board[k][l] !== 0) {
square.push(board[k][l]);
}
}
}
if (new Set(square).size !== square.length) {
return false;
}
}
}
return true;
}
console.table(solve(fourbyfour));
solve() keeps on returning undefined.
I'm fairly certain the issue is in the solve function, and not related to isSolved() and isValidBoard(). The solve function is getting the correct board, if I console.log the board instead of returning it, the correct board gets printed, but for some reason it isn't getting returned.
You are never returning the value of your recursion. You need to return from the second time you enter solve.
Also, console.table does not seams to be working in the snippet
const N = 4;
const fourbyfour = [
[1, 0, 0, 4],
[3, 4, 1, 2],
[2, 1, 4, 3],
[4, 3, 2, 1],
];
function solve(board) {
for (let i = 0; i < N; i++) {
for (let j = 0; j < N; j++) {
if (board[i][j] === 0) {
for (let k = 1; k < N + 1; k++) {
board[i][j] = k;
if (isValidBoard(board)) {
if (isSolved(board)) {
return board;
} else {
return solve(board);
}
}
}
}
}
}
return 'test';
}
function isSolved(board) {
let cells = [];
for (let row of board) {
cells.push(...row);
}
return !cells.includes(0);
}
function isValidBoard(board) {
// Check rows are valid
for (let i = 0; i < N; i++) {
const row = board[i].filter((cell) => cell !== 0);
if (new Set(row).size !== row.length) {
return false;
}
}
// Check columns are valid
for (let i = 0; i < N; i++) {
let column = [];
for (let j = 0; j < N; j++) {
if (board[j][i] !== 0) column.push(board[j][i]);
}
if (new Set(column).size !== column.length) {
return false;
}
}
const root = Math.sqrt(N);
// Check each grid
for (let i = 0; i < N; i += root) {
for (let j = 0; j < N; j += root) {
const square = [];
for (let k = i; k < i + root; k++) {
for (let l = j; l < j + root; l++) {
if (board[k][l] !== 0) {
square.push(board[k][l]);
}
}
}
if (new Set(square).size !== square.length) {
return false;
}
}
}
return true;
}
console.log(solve(fourbyfour));

Optimization (CodeWars Integers: Recreation One)

I managed to find two algos for this CodeWars challenge. Unfortunately, they are not fast enough (> 12000ms).
Any suggestions on how to improve my code?
v1 :
const listSquared = (m, n) => {
const result = [];
for (let i = m; i <= n; i++) {
const divisorsOfi = [];
for (let j = 0; j <= i; j++) {
if (i % j === 0) {
divisorsOfi.push(Math.pow(j, 2))
}
}
let sumOfDivisorsOfi = 1;
if (divisorsOfi.length > 1) {
sumOfDivisorsOfi = divisorsOfi.reduce((a, b) => a + b);
}
if (Number.isInteger(Math.sqrt(sumOfDivisorsOfi))) {
result.push([i, sumOfDivisorsOfi]);
}
}
return result;
}
v2:
const listSquared = (m, n) => {
const result = [];
for (let i = m; i <= n; i++) {
let sumOfSqrtDivisorsOfi = divisors(i);
if (Number.isInteger(Math.sqrt(sumOfSqrtDivisorsOfi))) {
result.push([i, sumOfSqrtDivisorsOfi]);
}
}
return result;
}
const divisors = (n) => [...Array(n + 1).keys()].slice(1)
.reduce((s, a) => s + (!(n % (a)) && Math.pow(a, 2)), 0);
I used v1 as a basis and modified it in the following way
const listSquared = (m, n) => {
const result = [];
for (let i = m; i <= n; i++) {
const divisorsOfi = [];
for (let j = 0; j <= Math.sqrt(i); j++) {
if (i % j === 0) {
divisorsOfi.push(Math.pow(j, 2));
if (i/j != j)
divisorsOfi.push(Math.pow(i/j, 2));
}
}
let sumOfDivisorsOfi = 1;
if (divisorsOfi.length > 1) {
sumOfDivisorsOfi = divisorsOfi.reduce((a, b) => a + b);
}
if (Number.isInteger(Math.sqrt(sumOfDivisorsOfi))) {
result.push([i, sumOfDivisorsOfi]);
}
}
return result;
}
The idea here is quite simple: if a could be divided by j then it's also could be divided by a/j so we need to check only sqrt(a) first numbers. The only thing you need to be careful is when you count result twice in case a/j and j is the same number.

Unable to push a function return in a loop

I have this function which returns an array of prime numbers:
function getPrimeFactors(n) {
var factors = [];
for (i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
var count = 0;
while (n % i === 0) {
n = n / i;
count++;
}
for (j = 1; j <= count; j++) {
factors.push(i);
}
}
}
if (n !== 1) {
factors.push(n);
}
return factors;
}
var numbers = [2, 3, 4, 5];
var array = [];
I want to get prime factors of all the numbers in the numbers array and push it into a new array (array)
for(i = 0; i < numbers.length; i++) {
array.push(getPrimeFactors(numbers[i]));
}
What am i doing wrong?
As mentioned by Damien Gold in the answer that was deleted, use var in your for-loops to make the variables local and to prevent your 2 functions from interfering with each other.
function getPrimeFactors(n) {
var factors = [];
for (var i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
var count = 0;
while (n % i === 0) {
n = n / i;
count++;
}
for (var j = 1; j <= count; j++) {
factors.push(i);
}
}
}
if (n !== 1) {
factors.push(n);
}
return factors;
}
And:
var numbers = [2, 3, 4, 5];
var array = [];
for(var i = 0; i < numbers.length; i++) {
array.push(getPrimeFactors(numbers[i]));
}
As a sidenote,
you are pushing arrays into your array instead of adding the values contained in your getPrimeFactors-array. If you instead want to push the resulting numbers into one array, try this:
for(var i=0; i<numbers.length; i++) {
array = array.concat(getPrimeFactors(numbers[i]));
}

Categories