Array by Reference vs Array by Value in Javascript - javascript

I'm reading Data Structures and Algorithms with Javascript by O'reily and it states the following:
Shallow copy (two arrays point to the same location in memory):
var nums = [];
for (var i = 0; i < 100; ++i) {
nums[i] = i+1;
}
var samenums = nums;
nums[0] = 400;
print(samenums[0]); // displays 400
Deep copy:
function copy(arr1, arr2) {
for (var i = 0; i < arr1.length; ++i) {
arr2[i] = arr1[i];
}
}
Now the following code fragment produces the expected result:
var nums = [];
for (var i = 0; i < 100; ++i) {
nums[i] = i+1;
}
var samenums = [];
copy(nums, samenums);
nums[0] = 400;
print(samenums[0]); // displays 1
Why is a function required in order to create deep copies?

As stated in the comments, the function is purely for aesthetics and reusability, and is not strictly necessary.
You could refactor your example:
function copy(arr1, arr2) {
for (var i = 0; i < arr1.length; ++i) {
arr2[i] = arr1[i];
}
}
var nums = [];
for (var i = 0; i < 100; ++i) {
nums[i] = i+1;
}
var samenums = [];
copy(nums, samenums);
nums[0] = 400;
print(samenums[0]); // displays 1
into this equivalent function-less example:
var nums = [];
for (var i = 0; i < 100; ++i) {
nums[i] = i+1;
}
var samenums = [];
for (var i = 0; i < nums.length; ++i) {
samenums[i] = nums[i];
}
nums[0] = 400;
print(samenums[0]); // displays 1

Related

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

Append element in JSobject

I am trying to create a JS object which has this structure
{ node1:
[ 'test1.1',
'test1.2'],
node2:
['test2.1',
'test2.2']
}
This is my code
for (var k = 0; k < keys.length; i++){
key = keys[k];
var result = {};
var r = [];
for (var i = 0; i < elements.length; i++){
r.push(elements[i]);
}
result[key] = r;
}
the result looks a bit different from my expectation and is not a valid JSON:
{ node1:
[ 'test1.1',
'test1.2'] }
{ node2:
[ 'test2.1',
'test2.2' ] }
I am not sure what is wrong about the code.
Declare var result = {}; outside the for loop and it will work as currently a new object is created inside the loop.
var result = {};
for (var k = 0; k < keys.length; k++) {
key = keys[k];
var r = [];
for (var i = 0; i < elements.length; i++) {
r.push(elements[i]);
}
result[key] = r;
}
You also have i++ in the first loop so change that to k++ otherwise there will be a infinite loop.

possible combinations get a targetTotal counting itself as a case

Trying to count possible combinations to get a targetTotal. Using powerSet returns the sum without adding itself. E.g [1,2,3,5] returns [3+1] for a targetSum of 4, whereas I expect to get [1+1+1+1], [2+2], [3+1].
Do you have any ideas how I could make it count itself first as a case?
function powerset(arr) {
var ps = [[]];
for (var i=0; i < arr.length; i++) {
for (var j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(arr[i]));
}
}
return ps;
}
function sum(arr) {
var total = 0;
for (var i = 0; i < arr.length; i++)
total += arr[i];
return total
}
function findSums(numbers, targetSum) {
var sumSets = [];
var numberSets = powerset(numbers);
for (var i=0; i < numberSets.length; i++) {
var numberSet = numberSets[i];
if (sum(numberSet) == targetSum)
sumSets.push(numberSet);
}
return sumSets;
}
Example invocation:
findSums([1,2,3,4,5],6); [[2,3], [1,4], [5], [1,1,1,1,1,1], [2,2,2], [3,3]]

Why does this code work with my array, but not when I typed in an array of strings? JavaScript

This code works when I have my array of arrays of numbers, but not when I typed in an array of arrays of strings; I did change the code to use .length afterward for the strings, but that helps. The error is with the line of "arr[i].reduce(function (onea, twoa) {" being an undefined function in the second version.
Oh, #user1600124, that prompt might be the error, even though I did still type in "[ ["one", "two", "three"], ["one1", "two2", "three3"] ]", it changed that all into a string. You have solved it, I think, but is there a way for user input without prompt. Thanks, #user1600124 for your solution!
var ArrayWidth = function(arr){
var ret = [], i;
for (i = 0; i < arr.length; i++) {
arr[i].reduce(function (onea, twoa) {
return ret[i] = Math.max(onea.length, twoa.length); //added ".length" to stings version
}, 0); //added ",0" to strings version
ret[i] = ret[i].toString().length;
}
return ret;
}
Working full code of array of arrays of numbers:
//Draws Non=Jagged Table with columns be the arrays in the array of arrays and the first being the heading.
var arrays = [
[111111, 22222, 333],
[444444444, 534334, 63],
[73, 83748395, 9343],
[279571, 327894598571490581, 34815, 2]
];
function ArrayHeight (arr) {
var ret = [], i, j;
for(i = 0; i < arr.length; i++){
window["a"+i] = arr[i];
ret[i] = window["a"+i];
for(j = 0; j < ret[i].length; j++)
ret[i][j] = ret[i][j].toString();
}
return ret;
}
var ArrayWidth = function(arr){
var ret = [], i;
for (i = 0; i < arr.length; i++) {
arr[i].reduce(function (onea, twoa) {
return ret[i] = Math.max(onea, twoa);
});
ret[i] = ret[i].toString().length;
}
return ret;
}
function addSpace (){
var ret = ArrayHeight(arrays);
console.log(ret);
var widthOfRet = ArrayWidth(arrays);
console.log(widthOfRet);
var i, j, k;
for(j = 0; j < ret.length; j++){
for(k = 0; k < (ret[j].length); k++){
for(i = ret[j][k].length; i < (widthOfRet[j] + 1); i++){
ret[j][k] = ret[j][k] + " ";
}
}
}
return ret;
}
var drawTable = function(){
var ret = addSpace();
var ArrayWid = ArrayWidth(arrays);
var table = "", retFirst = "", retSecond = "", totaled = 0, i, j;
for (i = 0; i < ArrayWid.length; i++)
totaled = totaled + ArrayWid[i];
for(i = 0; i < ret.length; i++)
retFirst = retFirst + ret[i][0];
for(i = 0; i < (totaled + ret.length); i++)
retSecond = retSecond + "-";
for(j = 0; j < ret.length; j++)
for(i = 0; i < ret[j].length; i++)
window["reti"+i] = "";
for(j = 0; j < ret.length; j++)
for(i = 0; i < ret[j].length; i++)
window["reti"+i] = window["reti"+i] + ret[j][i];
table = retFirst + "\n" + retSecond;
for(i = 1; window["reti"+i] != undefined; i++)
table = table + "\n" + window["reti"+i];
return table;
}
console.log(drawTable());
nonworking with array of arrays of strings:
//Draws Non-Jagged Table with columns be the arrays in the array of arrays and the first being the heading.
var arrays = prompt("To draw a table, type in an array of arrays. Each array is a column and the first is the heading. Cannot be jagged.", "[ [ , ... ], [, ... ], ... ]");
function ArrayHeight (arr) {
var ret = [], i, j;
for(i = 0; i < arr.length; i++){
window["a"+i] = arr[i];
ret[i] = window["a"+i];
for(j = 0; j < ret[i].length; j++)
ret[i][j] = ret[i][j].toString();
}
return ret;
}
var ArrayWidth = function(arr){
var ret = [], i;
for (i = 0; i < arr.length; i++) {
arr[i].reduce(function (onea, twoa) {
return ret[i] = Math.max(onea.length, twoa.length);
}, 0);
ret[i] = ret[i].toString().length;
}
return ret;
}
function addSpace (){
var ret = ArrayHeight(arrays);
console.log(ret);
var widthOfRet = ArrayWidth(arrays);
console.log(widthOfRet);
var i, j, k;
for(j = 0; j < ret.length; j++){
for(k = 0; k < (ret[j].length); k++){
for(i = ret[j][k].length; i < (widthOfRet[j] + 1); i++){
ret[j][k] = ret[j][k] + " ";
}
}
}
return ret;
}
var drawTable = function(){
var ret = addSpace();
var ArrayWid = ArrayWidth(arrays);
var table = "", retFirst = "", retSecond = "", totaled = 0, i, j;
for (i = 0; i < ArrayWid.length; i++)
totaled = totaled + ArrayWid[i];
for(i = 0; i < ret.length; i++)
retFirst = retFirst + ret[i][0];
for(i = 0; i < (totaled + ret.length); i++)
retSecond = retSecond + "-";
for(j = 0; j < ret.length; j++)
for(i = 0; i < ret[j].length; i++)
window["reti"+i] = "";
for(j = 0; j < ret.length; j++)
for(i = 0; i < ret[j].length; i++)
window["reti"+i] = window["reti"+i] + ret[j][i];
table = retFirst + "\n" + retSecond;
for(i = 1; window["reti"+i] != undefined; i++)
table = table + "\n" + window["reti"+i];
return table;
}
console.log(drawTable());
alert("Your table is in the console.log");
my html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script language="javascript">
//script was here
</script>
</body>
</html>
Thanks! :)
You are calling the reduce function on the content of the input array.
When you have array of arrays of numbers, arr[i] is an array, and hence has the reduce method
When you have array of strings, arr[i] is a string, and do not have the reduce method you tried to use. So you end up with errors
Try this:
function ArrayWidth(ary){
var r = [];
for(var i=0,l=ary.length; i<l; i++) {
r[i] = ary[i].reduce(function(a, b){
return Math.max(a, b);
}, 0);
}
return r;
}

Javascript can't convert undefined to object

I have the following code
for(i = 0; i < num; i++) {
var yPos = 10*i;
var numCells = wid/30;
for(j = 0; j < numCells; j++) {
blocks[i][j] = 1;
}
}
With
blocks = new Array();
However, when I execute the code I receive an error stating that:
can't convert undefined to object
Any ideas? :/
var blocks = [];
for(i = 0; i < num; i++) {
var yPos = 10*i;
var numCells = wid/30;
blocks[i] = []; // here is a fix
for(j = 0; j < numCells; j++) {
blocks[i][j] = 1;
}
}
In your particular case, since all the rows are initialised to be the same (a series of 1s), you can also do
var blocks = new Array(),
blockRow = new Array();
for (var i = 0; i < numCells; i++) {
blockRow.push(1);
}
for (var i = 0; i < num; i++) {
blocks.push(blockRow.slice()); // slice() makes a copy of blockRow
}

Categories