So I'm working on a project where objects are stored in an array. People can remove objects manually, but now I want to make so when an object is created it will be removed from the array after 5 seconds, only if it's still there (not manually removed). I'm using a settimeout where the object is spliced. How to do this that it will only remove the object if it's still there?
Edit:
So I wasn't very clear, when the timeout removes an object and it's not there anymore it just removes the next one like you'd expect.
Here's my code for remove the object manually:
if (intersect(player, food)) {
foods.splice(i, 1);
}
Here's the code of creating and removing with a timer:
food = {
x: x,
y: y,
};
foods.push(foods[i]);
setTimeout(function(){
foods.splice(i, 1);
}, 10000);
You have to check the index of the object in the array..
Array.indexOf() // returns -1 if its not there
function addToArrayAndRemoveAfter(object, array, removeAfterMs) {
array.push(object)
// remove after ms
setTimeout(() => {
var idx = array.indexOf(object);
idx > -1 && array.splice(idx, 1)
}, removeAfterMs)
}
Please add your code next time your asking something:
Its almost much harder to parse code out of human written text, then vice versa
Related
How would I call my method to my other objects?
Been having lots of trouble with everything I've tried.
I'm not that confident with this stuff, just looking on how to tell if the object is safe to drive or not.
//Create a constructor function called `Track`. It will accept two parameters - the name of the track and the maximum capacity of the track.
let track = function(name, capacity){
this.trackName=name
this.personnel=0;
this.cars=[];
this.cap=capacity;
}
//We'll need a value for the average weight of a person but this value will be the same for all tracks.
//Add a property `personWeight` on the `Track` prototype so that all instances share the same value.
track.prototype.personWeight = 200
//Create three methods on the prototype that will calculate track weight, person weight, and if its safe to drive
function personWeight(){
personnelWeight = this.personWeight * this.personnel
return personnelWeight
}
function trackWeight(){
let carsTotal = function myFunc(total, num) {
return total - num;
}
let weightTotal = (this.personnel * this.personWeight) + (this.carsTotal)
return weightTotal
}
function safeToDrive(){
if(this.trackWeight<this.capacity){
return true
}
}
//Create two track objects
let trackOne = new track ("Daytona", 25000);
trackOne.cars = [1800, 2400, 2700, 3200, 3600, 3800, 4200]
trackOne.personnel = 10
let trackTwo = new track ("Indiana",15000);
trackTwo.cars = [2000, 2300, 2800, 3000, 3500, 3700, 4000]
trackTwo.personnel = 8
//Call the `safeToDrive` method for truck objects.
With the code as it is now, you would use safeToDrive.call(trackOne). However, this is not the straight-forward way you would do it normally.
I guess what you really want is assigning these methods to the prototype:
track.prototype.safeToDrive = function () {
if(this.trackWeight<this.capacity){
return true
}
}
Then you'd call them using trackOne.safeToDrive().
The same goes for personWeight and trackWeight.
A few other observations:
Your check for this.capacity won't work because the property is actually called cap and not capacity according to what you set in your constructor.
safeToDrive currently returns true or nothing, i.e. undefined, and not true or false as you would expect.
You could fix that by either adding an else with return false or simply using return this.trackWeight < this.capacity instead of the whole if condition.
Oh, also, your personnelWeight variable is accidentally made global. Add a let before it. To avoid this in the first place, add 'use strict' at the top of your file to get warned about this issue next time.
I'm not sure what you are doing with carsTotal there though, I guess that should be a member function as well (otherwise you couldn't even call it using this.carsTotal as you do now). Plus, your indention is wrong there. (Put your file through a beautifier to see what I mean.)
Do you mean truck instead of track maybe...?
I've done some research on this issue. I am trying to manipulate an array of calculated values that looks like this in the console:
{nodeVoltages: Array(11), totalPower: Array(1), xlength: Array(11)}
nodeVoltages: Array(11)
0:48
1:47.71306060387108
2:47.250273223993105
3:46.59686907269243
4:45.71876416434013
5:44.53304242029258
6:42.745236969423615
7:Complex {re: 40.38334500994142, im:1.919295696316476, __ember1513267958317: "ember368"}
8:Complex { re:39.55961661806138, im:3.8933604519196416, __ember1513267958317: "ember369"}
This array is created dynamically through some math that I've come up with so there is no input data that I can give you. I'm trying to make the above array look like this:
{nodeVoltages: Array(11), totalPower: Array(1), xlength: Array(11)}
nodeVoltages: Array(11)
0:48
1:47.71306060387108
2:47.250273223993105
3:46.59686907269243
4:45.71876416434013
5:44.53304242029258
6:42.745236969423615
7:40.38334500994142
8:39.55961661806138
Using mathjs, I was able to evaluate my expressions and dynamically add the values into an array with the array.push command and display them. However, my code breaks once the imaginary values pop up in the results of my array.
How can I remove these imaginary numbers from my array? In other words, I need to remove the "im:" parts of the values when they begin to appear before I push them to the displayed array.
I tried to do this with some code I found from a previous answer to someone else's question (How do I remove a particular element from an array in JavaScript?) splice command like this:
var nodeVoltage2 = parser.eval(expression2);
//checks if there are imaginary values and removes them
if ("im" in nodeVoltage2) {
nodeVoltage2.splice(2,1)
}
//adds value to result array for analysis
nodeVoltages.push(nodeVoltage2);
but it returns in the console that "im is not defined".
Any help is greatly appreciated!
You can use the array map function.
Basically, we loop through the array. If the item has a .re property, we take that value only. If there is no .re property, we keep the value as is.
We can either write that in shorthand, as with result using the ternary operator and arrow function, or we can write it in a slightly more verbose but traditional way, as with resultTwo
let data = [
48
,47.71306060387108
,47.250273223993105
,46.59686907269243
,45.71876416434013
,44.53304242029258
,42.745236969423615
,{re: 40.38334500994142, im:1.919295696316476, __ember1513267958317: "ember368"}
,{ re:39.55961661806138, im:3.8933604519196416, __ember1513267958317: "ember369"}
]
let result = data.map((x) => x && x.re ? x.re : x);
let resultTwo = data.map(function(elem) {
// First, we need to check that the array element is not null / undefined
// We then need to check that it has a property called re that is also not null / undefined
if (elem != null && elem.re != null) {
// Just return the property we're interested in
return elem.re;
} else {
// Return the element as is
return elem;
}
});
console.log(result);
console.log(resultTwo);
Given an example input:
[
{"id":1,"currentBlack":1,"currentWhite":0,"max":1},
{"id":2,"currentBlack":0,"currentWhite":1,"max":1},
]
Output all possible states of the input where currentBlack and currentWhite can have a value anywhere in the range from their initial value up to the maximum value.
Correct output for this example:
[
[
{"id":1,"currentBlack":1,"currentWhite":0,"max":1},
{"id":2,"currentBlack":0,"currentWhite":1,"max":1},
],
[
{"id":1,"currentBlack":1,"currentWhite":1,"max":1},
{"id":2,"currentBlack":0,"currentWhite":1,"max":1},
],
[
{"id":1,"currentBlack":1,"currentWhite":1,"max":1},
{"id":2,"currentBlack":1,"currentWhite":1,"max":1},
],
[
{"id":1,"currentBlack":1,"currentWhite":0,"max":1},
{"id":2,"currentBlack":1,"currentWhite":1,"max":1},
]
]
The real input will have max anywhere between 1 and 8 and there will be far more objects within the input array. My attempt is below (heavily commented):
function allPossibleCounts(pieceCounts) {//pieceCounts is the input
var collection = []; //used to collect all possible values
recursiveCalls(pieceCounts); //runs recursive function
return collection; //returns result
function recursiveCalls(pieceCounts) {
//if pieceCounts is already in collection then return, not yet implemented so duplicates are currently possible
collection.push(pieceCounts);//inputs a potential value
console.log(JSON.stringify(pieceCounts));//this is successfully logs the correct values
console.log(JSON.stringify(collection));//collection isn't correct, all values at the top of the array are copies of each other
for (let n in pieceCounts) {//pieceCounts should be the same at the start of each loop within each scope, aka pieceCounts should be the same at the end of this loop as it is at the start
subBlackCall(pieceCounts);
function subBlackCall(pieceCounts) {
if (pieceCounts[n].currentBlack < pieceCounts[n].max) {
pieceCounts[n].currentBlack++;//increment
recursiveCalls(pieceCounts);
subBlackCall(pieceCounts);//essentially you're either adding +1 or +2 or +3 ect all the way up to max and calling recursiveCalls() off of each of those incremented values
pieceCounts[n].currentBlack--;//decrement to return pieceCounts to how it was at the start of this function
}
}
subWhiteCall(pieceCounts);
function subWhiteCall(pieceCounts) {
if (pieceCounts[n].currentWhite < pieceCounts[n].max) {
pieceCounts[n].currentWhite++;
recursiveCalls(pieceCounts);
subWhiteCall(pieceCounts);
pieceCounts[n].currentWhite--;
}
}
}
}
}
But currently my attempt outputs as this ungodly mess of copied arrays
[[{"id":1,"currentBlack":1,"currentWhite":1,"max":1},{"id":2,"currentBlack":1,"currentWhite":1,"max":1}],[{"id":1,"currentBlack":1,"currentWhite":1,"max":1},{"id":2,"currentBlack":1,"currentWhite":1,"max":1}],[{"id":1,"currentBlack":1,"currentWhite":1,"max":1},{"id":2,"currentBlack":1,"currentWhite":1,"max":1}],[{"id":1,"currentBlack":1,"currentWhite":1,"max":1},{"id":2,"currentBlack":1,"currentWhite":1,"max":1}],[{"id":1,"currentBlack":1,"currentWhite":1,"max":1},{"id":2,"currentBlack":1,"currentWhite":1,"max":1}]]
Edit: working code: https://pastebin.com/qqFTppsY
The pieceCounts[n] always reference to the one object. You should recreate the pieceCount for saving in to the collection as different object. For example, you can add
pieceCounts = JSON.parse(JSON.stringify(pieceCounts)); // just clone
at the start of recursiveCalls function.
To avoid conversion to JSON and back, I would suggest using Object.assign to perform a deeper copy in combination with map on the array:
function allPossibleCounts(pieceCounts) {
var result = [],
current = deeperCopy(pieceCounts);
function deeperCopy(arr) {
return arr.map( row => Object.assign({}, row) );
}
function recurse(depth) {
// depth: indication of which value will be incremented. Each "row" has
// 2 items (black/white), so when depth is even, it refers to black, when
// odd to white. Divide by two for getting the "row" in which the increment
// should happen.
var idx = depth >> 1, // divide by 2 for getting row index
prop = depth % 2 ? 'currentWhite' : 'currentBlack', // odd/even
row = pieceCounts[idx];
if (!row) { // at the end of the array
// Take a copy of this variation and add it to the results
result.push(deeperCopy(current));
return; // backtrack for other variations
}
for (var value = row[prop]; value <= row.max; value++) {
// Set the value of this property
current[idx][prop] = value;
// Collect all variations that can be made by varying any of
// the property values that follow after this one
recurse(depth+1);
// Repeat for all higher values this property can get.
}
}
recurse(0); // Start the process
return result;
}
// Sample input
var pieceCounts = [
{"id":1,"currentBlack":1,"currentWhite":0,"max":1},
{"id":2,"currentBlack":0,"currentWhite":1,"max":1},
];
// Get results
var result = allPossibleCounts(pieceCounts);
// Output
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The idea is to use recursion: imagine the problem can be solved for all variations that can be made for all properties, except the first one. Produce those, and then change the first property value to the next possible value. Repeat again the production of all variations, etc. The combination of all those results together will be the solution for when the first property value should also be varied.
This is an ideal situation for recursion. The recursion stops when there are no more property values remaining: in that case there is only one solution; the one with all the values set as they are. It can be added to the list of results.
The properties can be enumerated like this:
row currentBlack currentWhite
---------------------------------
0 0 1
1 2 3
2 4 5
3 6 7
...
n 2n-2 2n-1
We could call that number depth, and increase it at every step of deeper recursion. Given a depth, the property to vary is defined by:
depth is even => currentBlack
depth is odd => currentWhite
row number = depth / 2 (ignoring the remainder)
I am new in JavaScript, And I am trying to map my controller's buttons and leds for mixxx application. Is that an object, an array? var is missing.
BehringerCMDMM1.leds = [
// Master
{ "shiftButton" : 0x12 },
// Deck 1
{ "sync" : 0x30 },
// Deck 2
{ "sync" : 0x33 }
];
I have an error here,
BehringerCMDMM1.shiftButton = function (channel, control, value, status, group) {
// Note that there is no 'if (value)' here so this executes both when the shift button is pressed and when it is released.
// Therefore, BehringerCMDMM1.shift will only be true while the shift button is held down
var deck = BehringerCMDMM1.groupToDeck(group);
BehringerCMDMM1.shift = !BehringerCMDMM1.shift // '!' inverts the value of a boolean (true/false) variable
BehringerCMDMM1.setLED(BehringerCMDMM1.leds[deck]["shiftButton"], BehringerCMDMM1.shift);
}
about "shiftButton" as undefined.
also I have this function
BehringerCMDMM1.setLED = function(value, status) {
status = status ? 0x7F : 0x00;
midi.sendShortMsg(0x94, value, status);
}
This is from a javascript file I found on the internet created for a different controller. So, I am trying things to understand how can I configure mine.
BehringerCMDMM1.leds is an array of objects. Within that array, the element at index 0 is an object that has a shiftButton property. Thus, the only way to get the 0x12 value in your example is to do this:
BehringerCMDMM1.leds[0]['shiftButton']
So when this code executes...
var deck = BehringerCMDMM1.groupToDeck(group);
...the value of deck is probably something other than 0, and you're accessing one of the sync objects in the BehringerCMDMM1.leds array. For example, if the value of deck was 1, then this...
BehringerCMDMM1.leds[deck]['shiftButton']
...will be undefined because you're effectively doing this:
BehringerCMDMM1.leds[1]['shiftButton']
Ok,
I am new in JavaScript, And I am trying to map my controller's buttons and leds for mixxx application. Is that an object, an array?
You have a array of objects.
var is missing.
You should test what is inside yout deck variable. Try this:
console.log(deck);
if (deck in BehringerCMDMM1.leds) {
BehringerCMDMM1.setLED(BehringerCMDMM1.leds[deck]["shiftButton"], BehringerCMDMM1.shift);
} else {
console.log("Index: "+deck+" doesn't exist");
}
I have a grid of pictures on a page. And, periodically, I want to randomly swap one out for one of 50 I have in an array of Objects- but only if they're not already in the grid. This last part is what my code is failing to do.
I first get all 50 items, and put them into an allmedia array:
// initialize
var allmedia = getAllMedia();
var imagesInGrid = [];
When I place the items in the grid, I add to an array of grid items:
imagesInGrid.push(allmedia [i]); // while looping to fill DOM grid
Then, every 8 seconds I run a getRandomImage() routine that randomly gets an image from the allmedia array and then tests it to see if it's not already in the DOM.
function getRandomImageNotInGrid(){
var randomNumber = Math.floor(Math.random() * allmedia.length);
if (!isInArray(allmedia[randomNumber], imagesInGrid)) {
return allmedia[randomNumber];
} else {
return getRandomImageNotInGrid();
}
}
function isInArray(item, arr) {
if(arr[0]===undefined) return false;
for (var i=arr.length;i--;) {
if (arr[i]===item) {
return true;
}
}
return false;
}
But when I step through the code the (arr[i]===item) test is failing. I can see that the two objects are exactly the same, but the === isn't seeing this as true.
Is this a ByReference / ByValue issue? What am I doing wrong?
console.log:
arr[i]===item
false
arr[i]==item
false
typeof item
"object"
typeof arr[i]
"object"
Edit::
In the output below, I don't understand why arr[0] is not the same as 'item'. I use the exact same object that I put into allmedia as I do when I place the item into the page and, accordingly update imagesInGrid.
console.dir(arr[0]);
Object
caption: Object
comments: Object
created_time: "1305132396"
filter: "Poprocket"
id: "69204668"
images: Object
likes: Object
link: "http://instagr.am/p/EH_q8/"
location: Object
tags: Array[2]
type: "image"
user: Object
__proto__: Object
console.dir(item);
Object
caption: Object
comments: Object
created_time: "1305132396"
filter: "Poprocket"
id: "69204668"
images: Object
likes: Object
link: "http://instagr.am/p/EH_q8/"
location: Object
tags: Array[2]
type: "image"
user: Object
__proto__: Object
Instead of randomly selecting one from allmedia, can you instead remove one from allmedia?
var randomNumber = Math.floor(Math.random() * allmedia.length);
imagesInGrid.push(allmedia.splice(randomNumber,1));
When you use ===, you are comparing the objects by reference. What type of objects are you using to compare? Are you sure they are the same object reference? For example, if you are using strings, you may want to use == instead of ===. If you are using DOM objects, you will want to compare the source, as Alxandr suggested.
Also, your for loop syntax appears to be wrong:
for (var i=arr.length;i--;)
Should be:
for (var i=arr.length - 1; i >= 0; i--)
...if I'm not mistaken.
You don't show any code for how the image "objects" are created or how they are added and removed from the DOM. If you are creating image elements and storing references in an array, then replacing the DOM element with the one from the array, then the comparision should work.
However, if your image object is a bundle of data that is used to create an image element for display, then they will never be equal to each other. Every javascript object is unique, it will only ever be equal to itself.
But I suspect the simplest solution is that suggested by ic3b3rg - remove the object from allMedia when you select it, that way you don't have to test if it's already in imagesInGrid because you can only select each image once. If you want the display to go on forever, then when allmedia is empty, put all the images from imagesInGrid back into it and start again.
Edit
Your problem is the for loop. When you set :
for (var i=arr.length;i--;) {
// On first iteration, i=arr.length
// so arr[i] is undefined
}
i is not decremented until after the first loop, so set i=arr.length-1. It is more common to use while with a decrementing counter:
var i = arr.length;
while (i--) {
// i is decremented after the test
}