I am using this script to remove JSON objects from an array, which both appear within the array and another JSON object:
var stageChildren = stage.sprites;
for (var i = 0; i < stageChildren.length; i++) {
for (var x in mainMenu) {
if (mainMenu[x] === stageChildren[i]) {
console.log(x);
}
}
}
To make this more understandable, lets say I had two objects called: object1 & object2.
Inside object1, there may be the same JSON object which also appears within object2. If that's the case, the object is removed from object1.
While this script works, I think it might have a huge impact on performance. Why? Well, there's about 50 separate objects within stageChildren, and 10 inside mainMenu. The script loops through the first object inside stageChildren, checks if that object is also inside mainMenu (by performing a for loop again), and moves onto the next 49 objects.
Is there a more optimized way of doing this?
var index = 0;
var stageChildren = stage.sprites;
for (var x in mainMenu) {
if (stageChildren.includes(mainMenu[x])) {
const result = stageChildren.includes(mainMenu[x])
var index = stageChildren.indexOf(result);
stageChildren.splice(index, 1);
}
}
Related
I am stumped.
I have an array of objects that looks like this:
arr = [{source:someID, target:someID},{source:someID, target:someID},...]
After a certain stage, the array’s length reaches around ~20000. At this point in the running of the code, each object within the array is entirely unique.
I need to go on and add further objects to the array but I don’t want any double ups. In this process, another array is looped over to create new objects when two objects share a similar key value. These new objects are then pushed to the above array. Is there a way to test so that the new objects are pushed to this array only if the above array doesn’t already contain an identical object.
I’m not the most proficient in JS, and still learning. So far, I thought of using a nested loop
let testArr = [{code: num, id:num},{code: num, id:num},{code: num, id:num},…] // object being looped over to create more objects for above arr
let testData = testArr;
let arr = [{{source:someID, target:someID},{source:someID, target:someID},...}] // array being added to
let len = testArr.length;
for (let i = 0; i < len; i++) {
let objectTest = testData.findIndex((e) => e.uniqueID.includes(testArr[i].uniqueID));
if (objectTest !== -1) {
if (testArr[i].id !== testData[objectTest].id) {
let testObj = {
source: testArr[i].id,
target: testData[objectTest].id,
};
for (let a = 0; a < arr.length; a++) {
if (deepEqual(arr[a], testObj) === false) {
const newLink = new Object();
newLink.source = testArr[i].id;
newLink.target = testData[objectTest].id;
arr.push(newLink);
}
}
}
}
}
For the deepEqual function I’ve tried numerous different iterations (most found on here) of functions designed to test if objects/arrays are identical and I don’t think those functions on their own are the trouble.
When running this code, I run out of memory (JavaScript heap out of memory) and the app terminates. Was originally running the browser but moved it to Node. If I increased the max ram node could use to 16gb, the app would still terminate with the code: Fatal JavaScript invalid size error 156627439.
What I’m stuck on is a valid way I can check the array to see if there is an identical object already present and then skipping over this if it is true.
Any pointers would be much appreciated.
The biggest issue I can see is inside this piece of code:
for (let a = 0; a < arr.length; a++) {
if (deepEqual(arr[a], testObj) === false) {
const newLink = new Object();
newLink.source = testArr[i].id;
newLink.target = testData[objectTest].id;
arr.push(newLink);
}
}
You are looping while a < arr.length, but you push in the same array, so the length increases. Moreover, you push an object for every entry if you don't find an equal object.
Let's say the are 10 elements and there isn't a single object as the one you want to check inside: on the first iteration deepEqual returns false and you push the element; repeat this step and you'll push 10 times the same element, and the arr.length is now 20, so there will be 10 more iterations where deepEqual returns true and you don't push a new object.
Now just image the same with 20000 elements.
You should just check if it exists in the array, THEN eventually push it.
Try replacing the above with the following solution:
const doesNotContainEqual = arr.every((obj) => !deepEqual(obj, testObj));
if (doesNotContainEqual) {
const newLink = new Object();
newLink.source = testArr[i].id;
newLink.target = testData[objectTest].id;
arr.push(newLink);
}
I'm working with P5.js and try to save some values in an array and than creating a copy of this array to manipulate.
Unfortunately It happens that when I manipulate the second array, also the original one changes, and I can't figure out why.
var particels = []
var particelsCopy = []
function calcInitialPositions(){
for (var i = 0; i < pixels.length; i+=4) {
if (pixels[i] == 0){
var x_ = i % width
var y_ = i / width / 2
var coords_ = {x : x_ , y : y_}
particels.push(coords_)
}
};
}
function setup() {
loadPixels()
calcInitialPositions();
particelsCopy = particels
}
function draw() {
for (var i = 0; i < particelsCopy.length; i++) {
particelsCopy[0].x = 99
};
console.log(particel[0].x)
}
Console prints 99
The = operator in Javascript assigns Objects, which includes arrays, by reference not by value. So the line:
particelsCopy = particels
is redefining particelsCopy to be an alias of particels.... after that point they are the same array. You need to copy the array by value like:
particelsCopy = particels.slice();
Note this is only a shallow copy, if the array contains objects or arrays they will be copied by reference, you will have to repeat this on child items (e.g. coords_ object, though for objects the pattern is copy = Object.assign({},original);).
To deep copy everything by value, you have to do this for every child level of object/arrays. Many libraries like jQuery have ready-built functions to help this.
You can use destructuring to copy objects in an array
particelsCopy = particels.map(obj => ({...obj}));
The line:
particelsCopy = particels
makes a copy of the array reference, not the elements in the array.
You need to allocate a new array object, then copy the elements. If the elements are objects, you will have to make a shallow (or deep) copy of them as well. This solution uses Object.assign() to make a shallow copy.
particelsCopy = [] // already done previously
for (var i=0; i<particels.length; i++){
particelsCopy[i] = Object.assign({}, particels[i]};
}
I am working on an exercise where I prompt the user for a list of names, store the list of names in an array, sort the array in ascending order, and print the list of names (one per line). When I do so, I see a numeric value displayed instead of one name per line. Why is this happening?
var namesArray = [];
do {
var names = prompt("Enter a name: ");
namesArray.push(names);
} while (names != "")
namesArray.sort();
for (var name in namesArray) {
document.write(name);
}
When you use this construct:
for (var name in namesArray) {
the value of name will be the index in the array (the property name). If you want the actual value in the array, you have to use that property name/index to get the value:
document.write(namesArray[name]);
Of course, you really should not iterate arrays that way in the first place because that iterates all the enumerable properties of the array object (potentially including non array elements) as you can see in this example. Instead, you should use a traditional for loop as in this code example that follows:
var namesArray = [];
do {
var names = prompt("Enter a name: ");
namesArray.push(names);
} while (names != "")
namesArray.sort();
for (var i = 0; i < namesArray.length; i++) {
document.write(namesArray[i]);
}
Other options for iterating the array:
namesArray.forEach(function(value) {
document.write(value)
});
Or, in ES6, you can use the for/of syntax which does actually work how you were trying to use for/in:
for (let value of namesArray) {
document.write(value);
}
You also may want to understand that using document.write() after the document has already been parsed and loaded will cause the browser to clear the current document and start a new one. I don't know the larger context this code fits in, but that could cause you problems.
First, in a for..in loop, here name represents the keys and not the values in your array (you should use namesArray[name])
Also there is another important thing to note. An array is not recommended to be looped through using for..in and if so, you should do it like this:
for (var key in array) {
if (array.hasOwnProperty(key)) {
// then do stuff with array[key]
}
}
The usual preferred ways to loop through an array are the following:
A plain for loop
for (var i = 0, l = array.length; i < l; i++) {
// array[i]
}
Or a higher order function with Array.prototype.forEach (IE9+ if you need compat with IE)
array.forEach(function (item) {
// do something with the item
});
If i declare this
var data = [];
data [300] = 1;
data [600] = 1;
data [783] = 1;
I have an array of length 784 but with only 3 defined items within it.
Since splice(300,1) would delete the item and the index but would also shift every consecutive position, how can i delete the object in the index 300 from the array without altering the order of the array so when i use
for(var x in data)
it can correctly iterate only 2 times, on the indexes 600 and 783?
i tried using data[300] = undefined but the index 300 was still iterated over.
You could use delete:
delete data[300];
This sets the value of the index to be undefined, but doesn't modify the element index itself.
See more about the delete operator here.
dsg's answer will certainly work if you're going to use an array. But, if your data is going to be as sparse as it is, I wonder if a plain Javascript object might be a better choice for such sparse data where you never want the index/key to change. Arrays are optimized for consecutive sequences of data starting with an index of 0 and for iterating over a sequence of values. And, they keep track of a .length property of the highest index used minus one.
But, since you aren't really doing any of that and given the way you are storing data, you aren't able to use any of the useful features of an array. So, you could do this instead with a plain Javascript object:
var data = {};
data [300] = 1;
data [600] = 1;
data [783] = 1;
delete data[300];
This would create an object with three properties and then would delete one of those properties.
You can then iterate over the properties on an object like this:
for (var prop in data) {
console.log(data[prop]);
}
A couple things to remember: 1) The property names are always strings so your numbers would show us as "600" in the prop variable in the above iteration. 2) Iterating with the for/in technique does not guarantee any order of the properties iterated. They could come in any order since properties on an object have no innate order.
You can delete that element from the array:
delete data[300];
The full example:
var data = [];
data [300] = 1;
data [600] = 1;
data [783] = 1;
delete data[300];
var result = "";
for (var x in data) {
result += "<div>" + x + "</div>";
}
document.getElementById("output").innerHTML = result;
<div id="output" />
Consider:
var main = []
Now I want to generate many (289 to be exact) Arrays to be elements in the main one. Each of these arrays will have be like:
var subobject = {x:"A", y:"B", terrain:"C", note:"D"}
Generating the values are no problem, and I can easily put those values in a already defined subobject = {} and push(), but I can't figure out how to iterate a script each time which creates a new object and then push() into var main.
The naming of the subobject is unimportant, I'm looking for solution inwhich I can pull specific information such as:
main[0].x // get x value of the subarray in 0 location in main
main[5].note// get note value of the subarray in 5 location in main
(would it make a difference if every array had the same name? since I would never access subobject directly (after being pushed into main), but through main[X].YYY or would it have to be via main[X].subarray[Y] ?)
for (var i = 0; i < 289; i++) {
main.push({x: getRandomX(), y: getRandomY(), terrain: getTerrain(), note: ""});
}
as long as you create new objects {} before you push them to the array it is ok.
it doesn't matter if you assign the new object to the same variable (ie subobject)
you access them later like this:
main[0].x // get the value of x of the first element
[x:"A", y:"B", terrain:"C", note:"D"] isn't valid javascript, I think you want an object here:
{x:"A", y:"B", terrain:"C", note:"D"}
And to push each generated value, you can use a for loop
for (var i = 0; i < 9; i++) {
//do something, for example, generate a value
}
Arrays are only numerically indexed.
If you want named keys you have to use objects.
Here's the wrong way to do it.
var main = [],
subobject = {x:"A", y:"B", terrain:"C", note:"D"};
for(var i=0; i<289; i++){
subobject["x"] = Math.random();
subobject["terrain"] = Math.random();
//continue adding values using keys
main.push(subobject);
}
The thing is if you just use the same object your going to access that object every time you iterate it, and you'll replace it's value.
So you should do it like this.
var main = [],
subobject = {};
for(var i=0; i<289; i++){
subobject = {};//new object to make for uniquness
subobject["x"] = Math.random();
subobject["terrain"] = Math.random();
//continue adding values using keys
main.push(subobject);
}
You access members like this.
main[0].x;//value of x at index 0
//next index
main[1].terrain;//value of terrain at index 1
Collisions will only happen if you set the same index twice.
main[2].x = "value";
main[2].x = "replace value by accident";
Unless you want to change the value for some reason.
A different index will always give you a different object if you set a different one each time.