JavaScript array of classes behaving as clones? [duplicate] - javascript

This question already has answers here:
Copy array by value
(39 answers)
Closed 2 years ago.
So I've been trying to implement a NEAT algorithm in JS, but I'm missing something because when I try to mutate the genomes in my population, they all come out with the same mutation, as in they behave as complete clones, every single genome is the same at the end. Not sure why the array of glasses seems to share connections and nodes when they each have been declared as a new object, I'm definitely missing something I just do not know what, here's the code:
let startingNode = [];
let inNode1 = new Node("INPUT", 0)
let inNode2 = new Node("INPUT", 0)
let outNode1 = new Node("OUTPUT", 100000)
startingNode.push(inNode1);
startingNode.push(inNode2);
startingNode.push(outNode1);
let startingGenome = new Genome([], startingNode);
let population = new Population(20, startingGenome);
class Population {
constructor(populationSize, startingGenome) {
this.populationSize = populationSize;
this.population = [];
let genomeThings = startingGenome.copyGenome();
while (this.population.length < this.populationSize) {
this.population.push(new Genome(genomeThings.connections, genomeThings.nodes));
}
this.mutate();
console.log(this.population);
}
mutate() {
for (let genome of this.population) {
if (Math.random() < MUTATION_RATE) {
`genome.weightMutation()
}
}
}
class Genome {
constructor(connections, nodes) {
this.connections = connections;
this.nodes = nodes;
}
copyGenome() {
return {connections: this.connections, nodes: this.nodes};
}

After visiting a similar question: How do I correctly clone a JavaScript object?
I realised the clone method was wrong and was copying the objects in the wrong way (I don't understand enough about it to explain it really). But after creating an empty genome, and individually pushing each connection and node I managed to get it so the connections and nodes in seperate genomes no longer comflict with each other, if anyone knows precisely why this happens I would love to know.
copyGenome() {
let clonedGenome = new Genome([], []);
for (let x = 0; x < this.connections.length; x++) {
clonedGenome.connections.push(this.connections[x]);
}
for (let x = 0; x < this.nodes.length; x++) {
clonedGenome.nodes.push(this.nodes[x]);
}
return clonedGenome;
}

Related

JavaScript for loop is pushing duplicates

I originally used for/of, like so:
for (let item of totalData) {
if (item) {
let comp1 = item.slice(0,item.length/2)
let comp2 = item.slice(item.length/2)
for (let char of comp1) if (comp2.includes(char)) {
arr.push(char)
}
}
}
I noticed that I was getting the wrong results, so I started console logging the char and the item. This led me to notice that there were items in the first array (totalData) for which this code was running multiple times.
Thus, I tried doing it the original way, changing it to for (let i = 0; i < totalData.length; i++) and assigning item as totalData[i]. This didn't change anything.
Finally, I tried this code:
let arr = [];
for (let i = 0; i < totalData.length; i++) {
let item = totalData[i];
if (item && item != totalData[i - 1]) {
let comp1 = item.slice(0,item.length/2)
let comp2 = item.slice(item.length/2)
for (let char of comp1) if (comp2.includes(char)) {
arr.push(char)
console.log(char,item)
}
}
}
It came out with seemingly just as many (97, although I guess I didn't check how many there were before) duplicates.
Is this a bug in devtools or did I do something wrong? I'm using Brave (Chromium) devtools to run this code.
Edit: to make this more reproducible, here's my full code with a fake array (because the array I'm using is way too long)
let totalData = ['testingt','stringhere','doesntmatttr'];
let arr = [];
for (let item of totalData) {
if (item) {
let comp1 = item.slice(0,item.length/2)
let comp2 = item.slice(item.length/2)
for (let char of comp1) if (comp2.includes(char)) {
arr.push(char)
}
}
}
console.log(totalData.length, arr.length)
Running this in my console, I got 3 and 5. Here's a screenshot of what happened with the data I was originally using:
Those strings (minus the characters at the beginning, those were the results) all appeared in my dataset, but only once each.
Edit 2: I'm trying to figure out what characters in each string are on both sides of it. The expected output for the example I gave (the arr) would be ['t','r','t'].
Okay I figured it out while responding to people because it made me look at the question more from an objective viewpoint rather than from the viewpoint of someone who's tryna make the code work.
The problem is that some of the strings in my data array (e.g. "cNzPBNpclllzHbmTNRhqCRTgjC") have a character on the first side of the string twice, and also have it on the second side. So, for this string, it would push "N" twice, because it's checking for each character in the first side of the string (so both Ns) whether or not one exists on the second side (and there is an N on the second side).
Fixed code:
for (let i = 0; i < totalData.length; i++) {
let item = totalData[i];
if (item && item != totalData[i - 1]) {
let comp1 = item.slice(0,item.length/2)
let comp2 = item.slice(item.length/2)
for (let char of comp1) if (comp2.includes(char)) {
arr[i] = char
}
}
}

Dynamic variable declaration. Is this even the right method?

A little new to JS so be gentle :)
I'm trying to create a program that holds 5000+ boolean values that dynamically change based on other vars.
const chars = "abcdefghijklmnopqrstuvwxyz0";
const charsC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0"
const maxNum = 48;
const maxTile = 6;
var tile1, tile2, tile3, tile4, tile5, tile6
// test vars
var tile4 = "A27"
var t4a27 = false
// this snippet will be in an interval loop
for (let i = 1; i <= maxTile; ++i) {
for (let n = 0; n < chars.length; ++n) {
for (let j = 1; j <= maxNum; ++j) {
// this obviously doesnt work
var t[i][`${chars[n]}`][j];
// ^ ^ ^
if (tile[i] == `${charsC[n]}${j}`) {
t[i][h][j] = true;
console.log(t4a27)
} else {
t[i][h][j] = false;
}
}
}
}
For clarification a better word than "tile" for the vars could be "sprite" rather because its a point on the sprite.
The basic concept is the tile vars are designed to output their current position as a string value e.g. "A27". Then this loop will take that information and scan each tile subset to be true/false. So if the sprite lower right quadrant is inside "A27" the output would be t4a27 = true
In practice I can do this with just a lot of code (over 20,000 lines) but I figured their has to be an easier way that requires far less code.
This is probably not the right approach for your problem.
If you really need to store this amount of variables, it is probably best to put them in an object like so:
var tiles = {}
var tileName = 'abc'
// Dynamic setting:
tile[tileName] = true
// Dynamic reading:
console.log(tile[tileName])
I am wondering if you really want to store 5000 variables or if there is another way to calculate them at the time you need time, but that requires a bit more knowledge of the problem.
Javascript doesn't have this kind of ability to reflect local variables.
What you can do is attach all those variables to a global object, and proceed with: Object.keys(your_object) and your_object[key_name_here] = ...
I think you should use a 2-dim array for this. Or use a regular array of booleans with the appropriate size and do the index-magic yourself.
As you said, you are running on coordinates. A-27 is the same as row(1)+field(27) -- considering A is 1
If your field is 500x100, you create an Array as such: let gamefield = Array(500*100);
Warning: I have not tested this for syntax errors, but you should get the idea.
let gamefield = Array(500*100);
// optional gamefield.fill(true);
let row = idx => idx * 500;
let posIdx = (r, c) => row(r) + c;
// there is a sprite with a tiles property that returns
// 4 index positions for the sprite's quadrants as [r,c]
let quadrants = sprite.tiles.reportPositions()
// filter the quadrants where the gamefield at r,c is true
// this might also be a good case for some() instead of filter()
let collisions = quadrants.filter(pos => return gamefield[posIdx(...pos)]);
// if there is any of these, you can kill the sprite.
if(collisions.length > 0) sprite.kill();

Javascript observer or proxy without all changes going through proxy

I'm writing a subclass of arrays in Javascript to have better support for matrix operations (I know others exist, this is partially for me to re-teach myself linear algebra), and what I want is to have some properties that are reset whenever any values in the matrix are adjusted. Some calculations like the determinant are computationally intensive, and I'd like to be able to store them to avoid re-calculation, but then they need to be reset to null whenever any matrix elements are changed.
Essentially, it seems like what i want is the deprecated Array.observe(). And the replacement, proxies, seem like a lot of overhead for this one thing. As alluded to in some of the comments on Detecting Changes in a Javascript Array using the proxy object that were not directly addressed, I don't want to have to access my matrices only ever through proxies. I use a lot of handy [i][j] indexing and [mat[i], mat[j]] = [mat[j], mat[i]] in the code I've written so far.
class Matrix extends Array {
constructor() {
var args = [];
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i])) {
args.push(new Matrix(...arguments[i]));
} else {
args.push(arguments[i]);
}
}
super(...args);
this._determinant = null;
}
determ(forceRecalculate = false) {
if (this._determinant === null || forceRecalculate) {
this.upperEchelon();
}
return this._determinant;
}
upperEchelon(reduced = false) {
//There's a lot of code here but in the process of doing this other thing
//you get 99% of the way to calculating the determinant so it does this
this._determinant = factor;
}
}
Basically, I want anything like mat[0][0] = 10 or mat.push([2,4,5]) that updates the values in the matrix to set mat._determinant = null. Or any equivalent method of flagging that it needs to be re-calculated next time it's asked for. I'm not opposed to using proxies necessarily if someone can help me figure out the implementation, I would just rather have this set-to-null-on-update property be inherent to my class functionality.
What I really want is a way to overload base methods like [] a la C# so the functions that do the updating would trigger this without changing syntax, but I've resigned myself to not having that in JS.
While a Proxy would work, it would also be pretty slow. A different approach would be for every method that needs to use the value of _determinant go through a different function first to check to see if the _determinant needs to be updated (and if so, updates it). This way, the expensive recalculation is not done every time the array changes, but only just in time for the result to be used. For example:
class Matrix extends Array {
constructor() {
var args = [];
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i])) {
args.push(new Matrix(...arguments[i]));
} else {
args.push(arguments[i]);
}
}
super(...args);
this._determinant = null;
}
// next method is effectively a recursive deep join
// could also use toString if it doesn't interfere with anything else
getString() {
const itemsStr = this.map((item) => (
item instanceof Matrix
? item.getString()
: item
))
.join(',');
const result = '[' + itemsStr + ']';
return result;
}
getDeterm() {
const newString = this.getString();
if (newString !== this._lastString) {
this._lastString = newString;
this.upperEchelon();
}
return this._determinant;
}
upperEchelon() {
console.log('running upperEchelon');
this._determinant = Math.random();
}
}
const m = new Matrix([2, 3, 4], 5);
console.log(m.getDeterm());
// Not calculated again:
console.log(m.getDeterm());
// Mutation, next call of getDeterm will run upperEchelon:
m[0][0] = 1;
console.log(m.getDeterm());

JS multidimensional array spacefield

i wanna generate a 3x3 field. I want to do this with JS, it shall be a web application.
All fields shall inital with false. But it seems so that my code is not working correctly, but i don't find my fault. The goal is, that every spacesector is accessible.
Thats my idea:
// define size
var esize = generateSpace(3);
}
space[i] = false is replacing the array with a single boolean value false, not filling in all the entries in array you just created. You need another loop to initialize all the elements of the array.
function generateSpace(x) {
var space = [];
for (var i = 0; i < x; i++) {
space[i] = [];
for (var j = 0; j < x; j++) {
space[i][j] = false;
}
}
return space;
}
Also, your for() loop condition was wrong, as you weren't initializing the last element of space. It should have been i < space.length.
And when it's done, it needs to return the array that it created.
Since I got somewhat bored and felt like messing around, you can also initialize your dataset as shown below:
function generateSpace(x) {
return Array.apply(null, Array(x)).map(function() {
return Array.apply(null, Array(x)).map(function() {
return false;
});
});
}
The other functions work equally well, but here's a fairly simply looking one using ES6 that works for any square grid:
function generateSpace(x) {
return Array(x).fill(Array(x).fill(false));
}

Add elements to 2D array in jquery [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to create a two dimensional array in JavaScript?
I want to push elements to 2D array,
My code is,
var results = [];
var resultstemp = [];
function bindlinks(aamt,id1) {
resultstemp=results;
imagesArray.push($("#image1").mapster("get"));
if(results.length==0)
{
results.push([id1]);
}
else
{
var ck=0;
var lng=results.length;
for (var i = 0; i < lng; i++) {
if(results[i]==id1)
{
ck=1;
results = jQuery.grep(results, function(value) {
return value != id1;
});
}
}
if(ck==0)
{
results.push(id1);
}
}
I want to push id as well as aamt to array. Here i am pushing only id to array. I am not sure about how to add aamt to second position in 2D array.
Help me please,
Thank you
Change the declaration as follows:
var results = new Array();
and change the push as follows:
results.push([id1,aamt]);
Hope it would help
The logic behind the method to push two separate values in the same array evenly is something like this:
var array = [];
function push(id1, aamt) {
for (var i= 0; i < 10; i++) {
if (i%2 == 0) {
array.push(id1);
}
else {
array.push(aamt);
}
}
}
push(10, 12);
console.log(array); // 10, 12, 10, 12.....
Take note i abstracted the code quite a bit, because for me was not too obvious what the code should have to do, but the principle is simple: use the modulo (%) operator to test if the value is odd or even. If odd add the first value if even add the second value.
Hope it helps.

Categories