How to remove some items by iterating over the array of objects? - javascript

I want to iterate through the array of object and remove some of them based on some condition.
I used splice for removing the items to preserve an orderly count of items.
Then each time the item removed I would decrease the count.
But for some reason it never works:
var arr=[{img:1},{img:2},{img:3},{img:4}];
for (var i=0, count= arr.length; i < count; ) {
if ( this.arr[i].img==3 ) {
this.arr.splice(i,1);
count--;
}else i++
};
alert(JSON.stringify(arr));
​
...any ideas?

Looping backwards should do the trick. This avoids using counters and resetting the counter when removing an entry due to the "retreating" values.
var i;
for (i = arr.length; i--;) {
if (arr[i].img === 3) {
arr.splice(i, 1);
}
};

Simpler to loop through the array backwards, then you don't have to adjust the iterator:
var i = arr.length;
while ( i-- ) {
if ( arr[i].img == 3 ) {
arr.splice(i,1);
}
}

I have dealt with this same difficulty before. My solution was to loop through the array and compose another array of elements to remove. loop through the list of elements to remove in reverse and remove them. This worked well for me.
Michael G.

You're referring to this.arr instead of just arr.
Delete the two this. from the code, and it works. :-)

try this loop, I haven't tested but should work.
var arr=[{img:1},{img:2},{img:3},{img:4}];
for (var i=arr.length-1; i >= 0; i--) {
if ( arr[i].img==3 ) {
arr.splice(i,1);
}
};
alert(JSON.stringify(arr));

Related

javascript : after calling the splice() control comes out from the loop

I have an array rosters and i want to alter this array according to some conditions. Here what I'm trying to do.
somefunction(callback) {
for (var i in this.rosters) {
var roster = this.rosters[i];
if (roster.age > 7200) {
this.rosters.splice(i, 1);
} else {
this.rosters[i].age = this.EMarshal.tu.getAgeOfTime(
this.EMarshal.tu.getMyTime(
this.EMarshal.tu.getMyDate(roster.date), roster.shifttime
)
);
console.log(this.rosters[i].age);
}
}
callback();
}
When the the if condition is true and splice is been called, control comes out of from loop and call callback(). But i want to run the loop for each values in the array.
plz carefully notice that there are rosters and roster 2 different variables.
Any idea why its happening and the solution will be usefull.
Thanks
It's just because you are trying to alter the array on which you are iterating.
So, just ad some logic to store the indexes as you have said you have tried.
Here is one suggestion
before getting into loop var index = [];
then your if condition
if (roster.age > 7200) {
index.push(i);
}
and then after the loop, remove those indexes from rosters
for (var j = index.length - 1; j > -1; j-- ) {
console.log(j);
this.rosters.splice(index[j], 1);
}
Remember to iterate the index from last index otherwise you will remove the 1st index and the trying to remove the last index from the rosters, but now you have removed the element from the array so the length is been changed.

How to match and remove an object from javascript array?

I am trying to delete an element based on string match for a object property but when I do a slice on the javascript array the array size decreases and indexes change. Please help e with a solution. Here is a jsfiddle link for the same.
Code
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
}
}
}
Add i--;
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
i--;
}
}
}
jsfiddle example
Assuming you don't have a problem with having undefined as the new value, then you could call delete[i]; instead of selection.splice(i, 1); in that case the length does not change and neither will the indices.
Both Abhi1964 and Loolooii solution seems to work fine and solve problem, but i would personally keep the filtered results in separate array instead of manipulating index/deleting value in the same array, reason being, separate array would make code look simpler to read and understand. Reviewer need not to understand the index manipulation or keep track of undefined.
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
var filteredResult = [];
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
}else{
filteredResult.push(item);
}
}
}
//use filtered result as per your need.
Note:
I have not run this code, if some error seems to be there, please feel free to edit.

Array iteration with iself

I have an array of values like:
["34.44","55.22","15.32","21.67","98.76","14.57"]
and I want to iterate between themselves like
Calculate(34.44, 55.22);
Calculate(34.44, 15.32);
Calculate(34.44, 21.67);
Calculate(34.44, 98.76);
Calculate(34.44, 14.57);
Calculate(55.22, 15.32);
Calculate(55.22, 21.67);
Calculate(55.22, 98.76);
and so on...
what would be best way to iterate them in Javascript?
I was easily thinking having two arrays with same values and interate between first array and second array but could exists a better way for performance...
Thanks in advance to everyone!
Cheers,
Luigi
for( var i=0; i<myarray.length; i++ ) {
for( var j=i+1; j<myarray.length; j++ ) {
Calculate( myarray[i], myarray[j] );
}
}
Array.forEach doesn't allow to do this kind of iteration, your best option is to just make two loops on the index:
for (var i=0; i<x.length; i++) {
for (var j=i+1; j<x.length; j++) {
... do whatever you need with x[i], x[j] ...
}
}
if instead you need to process x[a], x[a] pairs (i.e. the same element twice) and also both x[a], x[b] pair and x[b], x[a] pair then forEach can shorten the code (and probably will run faster).
x.forEach(function(x1){ x.forEach(function(x2){
... do whatever you weant with x1, x2 ...
})});
but note that forEach will iterate only over the elements that have been actually assigned, not in all the range 0..length-1. For example after
x = [];
x[2] = 42;
the loop x.forEach(...) will not iterate over the undefined elements x[0] and x[1].
You can use nested forEach methods on the array.
var array = ["34.44", "55.22", "15.32", "21.67", "98.76", "14.57"];
array.forEach(function(numberLeft, indexLeft) {
array.forEach(function(numberRight, indexRight) {
// skip previous numbers and itself
if (indexLeft >= indexRight)
return;
Calculate( numberLeft, numberRight );
});
});

JavaScript loop stops on "localStorage.removeItem"

Why is the "localStorage.removeItem" stopping the loop? If I remove "localStorage.removeItem" and only leave the "alert", it loops though whole thing, but with "localStorage.removeItem" it stops on the first match.
function removeTask() {
for (i=0; i < localStorage.length; i++){
checkbox = document.getElementById('utford'+i);
if (checkbox.checked == true) {
alert(i);
localStorage.removeItem(localStorage.key(i));
}
}
printList();
}
If you remove an item, the keys move down an index. You need to loop backwards.
function removeTask() {
for (var i=localStorage.length-1; i>=0; i--){
var checkbox = document.getElementById('utford'+i);
if (checkbox.checked == true) {
localStorage.removeItem(localStorage.key(i));
}
}
printList();
}
You are iterating on an array-like object while deleting its entries.
This cannot work as the entries order will be mixed up on each deletion.
Consider this example.
First iteration deletes entry #1:
Entry key value
#1 my-first-key my-first-value
#2 my-2nd-key my-2nd-value
Second iteration tries to delete entry #2:
Entry key value
#1 my-2nd-key my-2nd-value
??? ??? ???
From what I make of your code, I'd advise you to use string keys instead. You could then pick the same key name as your elements' IDs.

Why is my nested for loop not working as I expected?

I have trouble dealing with my for loops now, I'm trying to compare two datum, basically it will compare 2 items, then it will write the matches and the mismatches on the webpage.
I managed to write the matches on the webpage, it was working good. But there's a bug in my mismatch compare.
It wrote all the data on the webpage X times, here's my JS code:
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
var count = 0;
var count2 = 0;
for(var i = 0; i < i1.length; i++) {
for(var j = 0; j < i2.length; j++) {
if(i1[i] == i2[j]) {
newArray.push(i1[i]);
count++;
} if (i1[i] !== i2[j]) {
newArray2.push(i1[i]);
count2++;
}
}
}
count-=2;
count2-=2
writeHTML(count,count2, newArray, newArray2);
}
The result was horrible for the mismatches:
alt text http://www.picamatic.com/show/2009/03/01/07/44/2523028_672x48.jpg
I was expecting it to show the mistakes, not all the strings.
The issue you're seeing is because of the nested for loop. You are essentially doing a cross-compare: for every item in i1, you are comparing it to every item in i2 (remember that j starts again at 0 every time i advances... the two loops don't run in parallel).
Since I understand from the comments below that you want to be able to compare one array to the other, even if the items in each are in a different order, I've edited my original suggestion. Note that the snippet below does not normalize differences in case between the two arrays... don't know if that's a concern. Also note that it only compares i1 against i2... not both i1 to i2 and i2 to i1, which would make the task a little more challenging.
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++) {
var found = false;
for (var j = 0; j < i2.length; j++) {
if (i1[i] == i2[j]) found = true;
}
if (found) {
newArray.push(i1[i])
} else {
newArray2.push(i1[i])
}
}
}
As an alternative, you could consider using a hash table to index i1/i2, but since the example of strings in your comment include spaces and I don't know if you're using any javascript helper libraries, it's probably best to stick with the nested for loops. The snippet also makes no attempt to weed out duplicates.
Another optimization you might consider is that your newArray and newArray2 arrays contain their own length property, so you don't need to pass the count to your HTML writer. When the writer receives the arrays, it can ask each one for the .length property to know how large each one is.
Not directly related to the question but you should see this:
Google techtalks about javascript
Maybe it will enlighten you :)
Couple of things about your question. First you should use '!=' instead of '!==' to check inequality. Second I am not sure why you are doing decreasing counts by 2, suggests to me that there may be duplicates in the array?! In any case your logic was wrong which was corrected by Jarrett later, but that was not a totally correct/complete answer either. Read ahead.
Your task sounds like "Given two set of arrays i1 & i2 to find i1 {intersection} i2 and i1{dash} {UNION} i2{dash}) (Group theory notation). i.e. You want to list common elements in newArray and uncommon elements in newArray2.
You need to do this.
1) Remove duplicates in both the arrays. (For improving the program efficiency later on) (This is not a MUST to get the desired result - you can skip it)
i1 = removeDuplicate(i1);
i2 = removeDuplicate(i2);
(Implementation for removeDuplicate not given).
2) Pass through i1 and find i1{dash} and i1 {intersection} i2.
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++)
{
var found = false;
for (var j = 0; j < i2.length; j++)
{
if (i1[i] == i2[j])
{
found = true;
newArray.push(i1[i]); //add to i1 {intersection} i2.
count++;
break; //once found don't check the remaining items
}
}
if (!found)
{
newArray2.push(i1[i]); //add i1{dash} to i1{dash} {UNION} i2{dash}
count2++;[
}
}
3) Pass through i2 and append i2{dash} to i1{dash}
for(var x=0; x<i2.length; x++)
{
var found = false;
//check in intersection array as it'd be faster than checking through i1
for(var y=0; y<newArray.length; y++) {
if( i2[x] == newArray[y])
{
found = true;
break;
}
}
if(!found)
{
newArray2.push(i2[x]); //append(Union) a2{dash} to a1{dash}
count2++;
}
}
writeHTML(count,count2, newArray, newArray2);
I have a feeling that this has to do with your second comparison using "!==" instead of "!="
"!==" is the inverse of "===", not "==". !== is a more strict comparison which does not do any type casting.
For instance (5 != '5') is false, where as (5 !== '5') is true. This means it's possible that you could be pushing to both arrays in the nested loop, since if(i1[i] == i2[j]) and if(i1[i] !== i2[j]) could both be true at the same time.
The fundamental problem here is that a pair of nested loops is NOT the right approach.
You need to walk a pointer through each dataset. ONE loop that advances both as needed.
Note that figuring out which to advance in case of a mismatch is a much bigger problem than simply walking them through. Finding the first mismatch isn't a problem, getting back on track after finding it is quite difficult.

Categories

Resources