I know this is a basic question, I have limited knowledge in JS. Is there an alternative method to keep an array length fixed with queue feature. The array keep receiving data I want always to remove the first element of the array?
var a=Math.random;
var array=[];
if (array.length < 4) {
array.push(a);
} else {
array.shift();
}
console.log("array",array);
I was hoping if there is such thing as following:
var a=Math.random;
var array=[];
array.length=4
array.push(a);
console.log(array);
You've basically got it in your first code block there, it just requires a slight adjustment of the logic. If it's a queue then you should always push the new number. You should then test if the length is greater than 4, and if it is, then use .shift() as you have done here to remove the first element.
Related
Apology:
I apologize if this is a really basic question, I've looked around but since I never did get a very solid grounding in Javascript objects, I may be looking for answers in all the wrong places. That, and I don't have a solid enough grasp of Javascript to seperate out what is Javascript in all of the JQuery questions, and I don't want to use JQuery until I have a better understanding of Javascript in general. Thank you.
Problem:
I have a for loop that is going through an array of Google Map markers, to return them to active on the map I have open. The markers still exist somehow in the array because they return randomly when I iterate a couple times through this block of code. It will make it through one or two iterations of the loop, and then end. I added the hasOwnProperty test once I noticed the error, but this isn't skipping past the problem item in the array like I thought it should.
Question:
Why is my for loop skipping over objects in the array that I know are there?
//Code Loop
for (var i in removedMarkerArray)
{
//test for valid object
if (!removedMarkerArray[i].hasOwnProperty('title')) continue;
else alert("You dawg, this stuff passed.");
//the actual code doing real work, rather than testing.
if (removedMarkerArray[i].PD == PD)
{
removedMarkerArray[i].setMap(map);
placedMarkerArray.push(removedMarkerArray[i]);
removedMarkerArray.splice(i, 1);
}
}
//Example object in the array.
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
title: location.mouseover,
PD: location.PD
});
Thank you for reading through my question, and I'm looking forward to any answers.
for...in is meant to iterate over the Properties of an Object. Use a regular for loop if its meant to iterate through the indicies of an array.
This answer explains why: https://stackoverflow.com/a/5263872/1385467
If removedMarkerArray is a true Array you should use a classic for loop rather than for in. So you should be doing something of the sort:
for(var i = 0, n = removedMarkerArray.length; i < n; i++){
console.log(removedMarkerArray[i]); //check desired object in console for debugging
..code here
}
I like forEach for better readability as long as you are using a real Array.
removedMarkerArray.forEach(function(removedMarker, index) {
//test for valid object
if (!removedMarker.hasOwnProperty('title')) continue;
else console.log("You dawg, this stuff passed.");
//the actual code doing real work, rather than testing.
if (removedMarker.PD == PD)
{
removedMarker.setMap(map);
removedMarkerArray.splice(index, 1);
placedMarkerArray.push(removedMarker);
}
});
The problem with my code removing a marker from the map stems not from the fact that I used for...in instead of a true for loop, which the highest rated question stated, it stemmed from that I was skipping over items in my array. When I was originally writing this, I assumed for...in would protect me from that, but as far as this is concerned, it worked just like the loop below.
I added a decrement on the i variable, so that it would run through the same index again instead of skipping one. This is now touching on all of the markers in my arrays.
for (var i = 0; i < placedMarkerArray.length; i++)
{
if (placedMarkerArray[i].PD === PD)
{
placedMarkerArray[i].setMap(null);
console.log(placedMarkerArray[i]);
removedMarkerArray.push(placedMarkerArray[i]);
placedMarkerArray.splice(i, 1);
>> i--;
}
}
This question already has answers here:
remove all items in array that start with a particular string
(5 answers)
Closed 7 years ago.
I have this simple array
var array = ['x.89999', 'y.sisisis', 'x.585858'];
I want to remove all the items in the array starting by 'x.' so to return this array:
['y.sisisis']
How can i do this without having to loop or iterate all the entire array? (i know it's probably not possible so don't mind if not possible)
Is there some builtin / native code i can use?
Thanks
you may use array.filter()
var newArray = array.filter(function(item){
return item.indexOf('x.') !== 1;
});
there is no way to do this job without looping through the whole array.
The only case – array is sorted alphabetically. But sorting demands looping through too
Assuming that the items to be removed will always precede the other items alphabetically (ie x is before y), you can sort your array and then break the loop as soon as the non-x value has been found:
function filter(arr) {
arr.sort();
for (var i = 0, l = arr.length; i < l; i++) {
if (arr[i][0] !== 'x') {
break;
}
}
return arr.slice(i);
}
filter(arr); // logs: "Iterated to 5 of array length 9"
DEMO
Of course, as JazzCat mentions, this is no good if you only have one y value and it's right at the end of the array - you're still going to have to iterate over the whole array.
Alternate option is to use regular expression, something like this. Fix your regex according to your requirement.
var array = ['x.89999', 'y.sisisis', 'x.585858'];
var filtArr = array.filter(function(x){
return x.match("^[x].+$");
});
console.log(filtArr);
One different answer not using explicit iteration or Array.prototype.filter:
var array = ['x.89999', 'y.sisisis', 'x.585858'];
array = array.join("#").replace(/(#?x\.\w*)/g,"").replace(/^#/,"").split("#");
//["y.sisisis"]
Of course you will need to take care of the separator character.
The good point is that it works on old browsers (ie8) while Array.prototype.filter does not.
I want to maintain a list of things in javascript. This seems to be a non trivial problem in this language...
var things = []
// for adding:
things[things.length] = thing
// for removing:
delete (things[things.indexOf(thing)])
This kinda works, but I fear the adding is a bug. When a thing that is not at the end of the array gets removed, a following add operation will overwrite an existing element, right? Because length is the number of elements.
How to do the adding correctly? Or is there a better way to do this with plain javascript (no JQuery)?
I would recommend using push and splice. With push, you don't have to keep track of your last inserted index. Also, with splice, you actually remove the element from the array and you aren't just deleting the reference and making it null.
Something like this would work:
things.push(thing);
things.splice(index, 1);
For adding you want to use push, so things.push(yourThing);
Adding to an array:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
Removing from an array:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
I would use a loop.
var index;
var things= [];
for (index = 0; index < things.length; ++index) {
text += things[index];
}
I know there are several issues with JavaScript Array.push() method posted here, but I can't get the following example to work:
First of all, i got a global Array:
var results = new Array();
for (var i = 0; i < X.length; i++) {
results[i] = new Array();
}
Now this array should be filled on a button-event. All I want is to fill the Array with new Arrays and push some data to them. The following code should check if results[x][y] already is an Array (and create one if it's not) and push data to it.
So, in the end, there should be an Array (result) that contains X.length Arrays filled with an unknown number of new Arrays, each of them containing an unknown number of data:
function pushResult(result) {
if (typeof results[currentStim][currentDist] == 'undefined') {
results[currentStim][currentDist] = new Array();
}
results[currentStim][currentDist].push(result);
}
Problem is: It just doesn't work. I made sure that currentStim is never out of bounds, I made sure that the "if"-Statement is only accessed when needed (so the Array isn't overwritten with a new one) and I watched the return-value of push(), always throwring back a number representing the new array length. As expected, this number increases evertime a value is pushed to an Array.
However, when I finally call:
document.getElementById('results').value = JSON.stringify(results);
to pass results to my PHP-script, something like this will be passed:
[[],[[1]],[],[]]
push()was called MUCH more often than once (at least "1" is one of the results I wanted to be stored) and, as described, always returned an increasing arrayLength. How does that work? What happened to my data?
I testet this on Chrome as well as on Firefox, same result. It might be interesting that a seperate loop draws to a Canvas the same time, but that shouldn't interupt Array-Handling and onKey-Events, right?
Hope u can help me,
MA3o
EDIT:
pushResult is called like this:
// Handles Space-Events
function pushed(event) {
if (event.which == 32 && stimAlive) {
pushResult(1);
hitCurrent = true;
}
Where hitCurrent and stimAlive are just flags set somewhere else. Some code further the function pushedis registered as an event listener:
document.onkeydown = function(event) { pushed(event)}
All the functions are called correctly. Adding console.log(results) to every loop just shows the right Array, as far as I can see.
According to the comments, the problem might be that "currentDist" can be a float value.
How do I remove an items from a data bound array? My code follows.
for(var i = 0; i < listBox.selectedIndices.length; i++) {
var toRemove = listFiles.selectedIndices[i];
dataArray.splice(toRemove, 1);
}
Thanks in advance!
Edit Here is my swf. The Add Photos works except when you remove items.
http://www.3rdshooter.com/Content/Flash/PhotoUploader.html
Add 3 photos different.
Remove 2nd photo.
Add a different photo.
SWF adds the 2nd photo to the end.
Any ideas on why it would be doing this?
Edit 2 Here is my code
private function OnSelectFileRefList(e:Event):void
{
Alert.show('addstart:' + arrayQueue.length);
for each (var f:FileReference in fileRefList.fileList)
{
var lid:ListItemData = new ListItemData();
lid.fileRef = f;
arrayQueue[arrayQueue.length]=lid;
}
Alert.show('addcomplete:' + arrayQueue.length);
listFiles.executeBindings();
Alert.show(ListItemData(arrayQueue[arrayQueue.length-1]).fileRef.name);
PushStatus('Added ' + fileRefList.fileList.length.toString() + ' photo(s) to queue!');
fileRefList.fileList.length = 0;
buttonUpload.enabled = (arrayQueue.length > 0);
}
private function OnButtonRemoveClicked(e:Event):void
{
for(var i:Number = 0; i < listFiles.selectedIndices.length; i++) {
var toRemove:Number = listFiles.selectedIndices[i];
//Alert.show(toRemove.toString());
arrayQueue.splice(toRemove, 1);
}
listFiles.executeBindings();
Alert.show('removecomplete:' + arrayQueue.length);
PushStatus('Removed photos from queue.');
buttonRemove.enabled = (listFiles.selectedItems.length > 0);
buttonUpload.enabled = (arrayQueue.length > 0);
}
It would definitely be helpful to know two things:
Which version of ActionScript are you targeting?
Judging from the behavior of your application, the error isn't occurring when the user removes an item from the list of files to upload. Looks more like an issue with your logic when a user adds a new item to the list. Any chance you could post that code as well?
UPDATE:
Instead of: arrayQueue[arrayQueue.length]=lid
Try: arrayQueue.push(lid)
That will add a new item to the end of the array and push the item in to that spot.
UPDATE 2:
Ok, did a little more digging. Turns out that the fileList doesn't get cleared every time the dialog is opened (if you're not creating a new instance of the FileReferenceList each time the user selects new files). You need to call splice() on the fileList after you add each file to your Array.
Try something like this in your AddFile() method...
for(var j:int=0; j < fileRefList.fileList.length; j++)
{
arrayQueue.push(fileRefList.fileList[j]);
fileRefList.fileList.splice(j, 1);
}
That will keep the fileList up to date rather than holding on to previous selections.
I see one issue. The selected indices are no longer valid once you have spliced out the first element from the array. But that should only be a problem when removing multiple items at once.
I think we need to see more code about how you are handling the upload before we can figure out what is going on. It looks to me like you are holding a reference to the removed FileReference or something. The described problem is occurring when you upload a new file, not when you remove the selected one.
Do you mean to use listBox and listFiles to refer to the same thing?
I'm stepping out on a limb here, because I don't have a ton of experience with JavaScript, but I'd do this the same way that I'd do it in C, C++, or Java: By copying the remaining array elements down into their new locations.
Assuming that listFiles.selectedIndices is sorted (and its contents are valid indices for dataArray), the code would be something like the following:
(WARNING: untested code follows.)
// Don't bother copying any elements below the first selected element.
var writeIndex = listFiles.selectedIndices[0];
var readIndex = listFiles.selectedIndices[0] + 1;
var selectionIndex = 1;
while(writeIndex < (dataArray.length - listFiles.selectedIndices.length)) {
if (selectionIndex < listFiles.selectedIndices.length) {
// If the read pointer is currently at a selected element,
// then bump it up until it's past selected range.
while(selectionIndex < listFiles.selectedIndices.length &&
readIndex == listFiles.selectedIndices[selectionIndex]) {
selectionIndex++;
readIndex++;
}
}
dataArray[writeIndex++] = dataArray[readIndex++];
}
// Remove the tail of the dataArray
if (writeIndex < dataArray.length) {
dataArray.splice(writeIndex, dataArray.length - writeIndex);
}
EDIT 2009/04/04: Your Remove algorithm still suffers from the flaw that as you remove items in listFiles.selectedIndices, you break the correspondence between the indices in arrayQueue and those in listFiles.selectedIndices.
To see this, try adding 3 files, then doing "Select All" and then hit Remove. It will start by removing the 1st file in the list (index 0). Now what had been the 2nd and 3rd files in the list are at indices 0 and 1. The next value taken from listFiles.selectedIndices is 1 -- but now, what had been the 3rd file is at index 1. So the former File #3 gets spliced out of the array, leaving the former 2nd file un-removed and at index 0. (Using more files, you'll see that this implementation only removes every other file in the array.)
This is why my JavaScript code (above) uses a readIndex and a writeIndex to copy the entries in the array, skipping the readIndex over the indices that are to be deleted. This algorithm avoids the problem of losing correspondence between the array indices. (It does need to be coded carefully to guard against various edge conditions.) I tried some JavaScript code similar to what I wrote above; it worked for me.
I suspect that the problem in your original test case (removing the 2nd file, then adding another) is analogous. Since you've only shown part of your code, I can't tell whether the array indices and the data in listFiles.selectedIndices, arrayQueue, and fileRefList.fileList are always going to match up appropriately. (But I suspect that the problem is that they don't.)
BTW, even if you fix the problem with using splice() by adjusting the array index values appropriately, it's still an O(N2) algorithm in the general case. The array copy algorithm is O(N).
I'd really need to see the whole class to provide a difinitive answer, but I would write a method to handle removing multiple objects from the dataProvider and perhaps assigning a new array as the dataProvider for the list instead of toying with binding and using the same list for the duration. Like I said, this is probably inefficient, and would require a look at the context of the question, but that is what I would do 9unless you have a big need for binding in this circumstance)
/**
* Returns a new Array with the selected objects removed
*/
private function removeSelected(selectedItems:Array):Array
{
var returnArray:Array = []
for each(var object:Object in this.arrayQueue)
{
if( selectedItems.indexOf(object)==-1 )
returnArray.push( object )
}
return returnArray;
}
You might be interested in this blog entry about the fact that robust iterators are missing in the Java language.
The programming language, you mentioned Javascript, is not the issue, it's the concept of robust iterators that I wanted to point out (the paper actually is about C++ as the programming language).
The [research document]() about providing robust iterators for the ET++ C++ framework may still e helpful in solving your problem. I am sure the document can provide you with the necessary ideas how to approach your problem.