javascript does not splice all the element of the array - javascript

http://jsfiddle.net/4wKuj/8/
var myarr=new Array("Saab","Volvo","BMW");
console.log(myarr);
for (var i=0; i<myarr.length; i++) {
myarr.splice(i,1);
}
console.log(myarr);
Note: in the real implementation I am not trying to empty the array so plz do not suggest other way of emptying an array.
Why I still see "volvo" in the console log ?
Should not it be removed either , same as other ?
Thank You

What it does :
first iteration, i=0, removes "Saab", => array is ["Volvo","BMW"]
second iteration, i=1, removes "BMW" because this is what you have at index 1

After the first splice:
i = 1
myarr = ["Volvo", "BMW"]
So it will remove "BMW". After the second splice:
i = 2
myarr = ["Volvo"]
And the loop will not continue. Better do it like this:
while (myarr.length > 1) {
myarr.splice(0, 1);
}

before loop, your array looks like
["Saab","Volvo","BMW"]
after first iteration of loop you delete first element of array, and now array looks like
["Volvo","BMW"]
during second iteration your "i" variable has '1' (one) value that corresponds to second element of array, in other words you say:
delete in ["Volvo","BMW"] array element with index '1'

If you remove an item from the array, you also need to adjust the index value, f.ex:
var myarr=new Array("Saab","Volvo","BMW");
for (var i=0; i<myarr.length; i++) {
myarr.splice(i--,1);
}
Tip: If you are using a loop remove items from an array based on it’s value, you can use other methods, f.ex Array.filter:
myarr = myarr.filter(function(val) {
return val !== 'Volvo'
});
Array.indexOf also comes to mind.

Related

how to delete an entire element from an associative array in javascript

I am not too good in javascript.I have an associative array in which I am putting some values.Now to iterate through the array I am using a foreach loop.Inside the foreach loop, if a condition is met I want to delete the entire element and want no empty space in the array for efficiency.However I have no idea how to get the index of an array from a foreach loop.
here is my code:
for(var j = 0 ; j < i; j++){
obstacles.push({ width:35, height:35, x:initialX, y:initialY});
}
//to iterate through the array
obstacles.forEach(o => {
o.x -= 2;
context.fillRect(o.x, o.y, o.width, o.height); //create a rectangle with the elements inside the associative array
//I need to get the index and delete the entire element and afterwards the array should resize with the other elements' index updated
}
To remove elements that comply to a certain condition from an array, Array.filter comes in handy. See MDN
let arr1 = [1,2,3,4,5,6,7,8,9,10];
// [...] to stuff to arr1
arr1 = arr1.filter(val => val % 2 === 0);
console.log(arr1);

Looping through items in an array of objects

I have an array of objects.
ABC.getAggregation("V")[0].getItems();
this produces the result:
MY ARRAY OF OBJECTS
In the console i can get the result i am looking for by specifying the position of the item like this:
ABC.getAggregation("V")[0].getItems()[0].getPosition()
ABC.getAggregation("V")[0].getItems()[1].getPosition()
ABC.getAggregation("V")[0].getItems()[2].getPosition()
The result of the above code produces string values e.g "3.4554,43,0".
How can i loop through each item and get the position in my code. just like the above code that i typed in the console. there wont always be 3 objects this is why i cant hard code the above 3 lines.
Try using a the Array.prototype.forEach() function. The function will be called for each element in the array, passing in the element as the first parameter.
ABC.getAggregation("V")[0].getItems().forEach( function (item) {
item.getPosition();
//do something else
});
More on ".forEach()"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
You can treat it like any other array:
var myArray = ABC.getAggregation("V")[0].getItems();
for(var i=0; i< myArray.length; i++){
myArray[i].getPosition(); //Do something with the position.
}
You can use for loop to iterate trough all of them.
for(var i=0; i<ABC.getAggregation("V").getItems().length; i++) {
ABC.getAggregation("V")[0].getItems()[i].getPosition();
}
You can use forEach loop to iterate trough all of them.
ABC.getAggregation("V").getItems().forEach (item, index) {
return ABC.getAggregation("V")[0].getItems()[index].getPosition();
}
A very simple way to iterate through each object in the array is just with a for loop on the array, you don't even need to declare your iterating variable.
ex:
var anArray = ['one', 'two', 'three'];
for( i in anArray){
console.log('index #: ' + i );
console.log(anArray[i]);
}
will print out all the elements in anArray:
index #: 0
one
index #: 1
two
index #: 2
three
!! Apparently this is a good example of how not to do it :P
You can assign the items to an array and loop through them like this:
var items = ABC.getAggregation("V")[0].getItems();
var returnString = "";
for (var key in items ) {
if (items .hasOwnProperty(key)) {
var element = items [key];
returnString += element.getPosition() + ',';
}
}
returnString = returnString.substring(0, x.length-1);
console.log(returnString);

Why can't I remove item from this Array using slice or lodash remove?

Using slice (In this situation I find the correct item in the Array, attempt slice, but the Array stays exactly the same):
for (var i=0; i<vm.storedViews.length; i++) {
if (view_id === vm.storedViews[i].id) {
vm.storedViews.slice(i,1);
// vm.storedViews = _.remove(vm.storedViews, i);
break;
}
}
console.log('vm.storedViews',vm.storedViews);
Using _.remove all items end up being removed from my Array:
for (var i=0; i<vm.storedViews.length; i++) {
if (view_id === vm.storedViews[i].id) {
// vm.storedViews.slice(i,1);
vm.storedViews = _.remove(vm.storedViews, i);
break;
}
}
console.log('vm.storedViews',vm.storedViews);
Use .splice() to modify the array. .slice just returns the selected elements.
vm.storedViews.splice(i, 1);
_.remove() didn't work because the the second argument is not an index, it's a predicate function -- it removes all elements of the array for which the function returns a truthy value. It looks like the closest lodash function to .splice() is _.pullAt(). It takes a list of array indexes to remove, so you can use it for your case where you just want to remove one element:
_.pullAt(vm.storedViews, i);
Instead of your for loop you can use _.findIndex():
_.pullAt(vm.storedViews, _.findIndex(vm.storedViews, 'id', view_id));
If the IDs are unique, you can also use:
_.remove(vm.storedViews, 'id', view_id);

Loop to remove an element in array with multiple occurrences

I want to remove an element in an array with multiple occurrences with a function.
var array=["hello","hello","world",1,"world"];
function removeItem(item){
for(i in array){
if(array[i]==item) array.splice(i,1);
}
}
removeItem("world");
//Return hello,hello,1
removeItem("hello");
//Return hello,world,1,world
This loop doesn't remove the element when it repeats twice in sequence, only removes one of them.
Why?
You have a built in function called filter that filters an array based on a predicate (a condition).
It doesn't alter the original array but returns a new filtered one.
var array=["hello","hello","world",1,"world"];
var filtered = array.filter(function(element) {
return element !== "hello";
}); // filtered contains no occurrences of hello
You can extract it to a function:
function without(array, what){
return array.filter(function(element){
return element !== what;
});
}
However, the original filter seems expressive enough.
Here is a link to its documentation
Your original function has a few issues:
It iterates the array using a for... in loop which has no guarantee on the iteration order. Also, don't use it to iterate through arrays - prefer a normal for... loop or a .forEach
You're iterating an array with an off-by-one error so you're skipping on the next item since you're both removing the element and progressing the array.
That is because the for-loop goes to the next item after the occurrence is deleted, thereby skipping the item directly after that one.
For example, lets assume item1 needs to be deleted in this array (note that <- is the index of the loop):
item1 (<-), item2, item3
after deleting:
item2 (<-), item3
and after index is updated (as the loop was finished)
item2, item3 (<-)
So you can see item2 is skipped and thus not checked!
Therefore you'd need to compensate for this by manually reducing the index by 1, as shown here:
function removeItem(item){
for(var i = 0; i < array.length; i++){
if(array[i]==item) {
array.splice(i,1);
i--; // Prevent skipping an item
}
}
}
Instead of using this for-loop, you can use more 'modern' methods to filter out unwanted items as shown in the other answer by Benjamin.
None of these answers are very optimal. The accepted answer with the filter will result in a new instance of an array. The answer with the second most votes, the for loop that takes a step back on every splice, is unnecessarily complex.
If you want to do the for loop loop approach, just count backward down to 0.
for (var i = array.length - 0; i >= 0; i--) {
if (array[i] === item) {
array.splice(i, 1);
}
}
However, I've used a surprisingly fast method with a while loop and indexOf:
var itemIndex = 0;
while ((itemIndex = valuesArray.indexOf(findItem, itemIndex)) > -1) {
valuesArray.splice(itemIndex, 1);
}
What makes this method not repetitive is that after the any removal, the next search will start at the index of the next element after the removed item. That's because you can pass a starting index into indexOf as the second parameter.
In a jsPerf test case comparing the two above methods and the accepted filter method, the indexOf routinely finished first on Firefox and Chrome, and was second on IE. The filter method was always slower by a wide margin.
Conclusion: Either reverse for loop are a while with indexOf are currently the best methods I can find to remove multiple instances of the same element from an array. Using filter creates a new array and is slower so I would avoid that.
You can use loadash or underscore js in this case
if arr is an array you can remove duplicates by:
var arr = [2,3,4,4,5,5];
arr = _.uniq(arr);
Try to run your code "manually" -
The "hello" are following each other. you remove the first, your array shrinks in one item, and now the index you have follow the next item.
removing "hello""
Start Loop. i=0, array=["hello","hello","world",1,"world"] i is pointing to "hello"
remove first item, i=0 array=["hello","world",1,"world"]
next loop, i=1, array=["hello","world",1,"world"]. second "hello" will not be removed.
Lets look at "world" =
i=2, is pointing to "world" (remove). on next loop the array is:
["hello","hello",1,"world"] and i=3. here went the second "world".
what do you wish to happen? do you want to remove all instances of the item? or only the first one? for first case, the remove should be in
while (array[i] == item) array.splice(i,1);
for second case - return as soon as you had removed item.
Create a set given an array, the original array is unmodified
Demo on Fiddle
var array=["hello","hello","world",1,"world"];
function removeDups(items) {
var i,
setObj = {},
setArray = [];
for (i = 0; i < items.length; i += 1) {
if (!setObj.hasOwnProperty(items[i])) {
setArray.push(items[i]);
setObj[items[i]] = true;
}
}
return setArray;
}
console.log(removeDups(array)); // ["hello", "world", 1]
I must say that my approach does not make use of splice feature and you need another array for this solution as well.
First of all, I guess your way of looping an array is not the right. You are using for in loops which are for objects, not arrays. You'd better use $.each in case you are using jQuery or Array.prototype.forEach if you are using vanila Javascript.
Second, why not creating a new empty array, looping through it and adding only the unique elements to the new array, like this:
FIRST APPROACH (jQuery):
var newArray = [];
$.each(array, function(i, element) {
if ($.inArray(element, newArray) === -1) {
newArray.push(region);
}
});
SECOND APPROACH (Vanila Javascript):
var newArray = [];
array.forEach(function(i, element) {
if (newArray.indexOf(element) === -1) {
newArray.push(region);
}
});
I needed a slight variation of this, the ability to remove 'n' occurrences of an item from an array, so I modified #Veger's answer as:
function removeArrayItemNTimes(arr,toRemove,times){
times = times || 10;
for(var i = 0; i < arr.length; i++){
if(arr[i]==toRemove) {
arr.splice(i,1);
i--; // Prevent skipping an item
times--;
if (times<=0) break;
}
}
return arr;
}
An alternate approach would be to sort the array and then playing around with the indexes of the values.
function(arr) {
var sortedArray = arr.sort();
//In case of numbers, you can use arr.sort(function(a,b) {return a - b;})
for (var i = 0; sortedArray.length; i++) {
if (sortedArray.indexOf(sortedArray[i]) === sortedArray.lastIndexOf(sortedArray[i]))
continue;
else
sortedArray.splice(sortedArray.indexOf(sortedArray[i]), (sortedArray.lastIndexOf(sortedArray[i]) - sortedArray.indexOf(sortedArray[i])));
}
}
You can use the following piece of code to remove multiple occurrences of value val in array arr.
while(arr.indexOf(val)!=-1){
arr.splice(arr.indexOf(val), 1);
}
I thinks this code much simpler to understand and no need to pass manually each element that what we want to remove
ES6 syntax makes our life so simpler, try it out
const removeOccurences = (array)=>{
const newArray= array.filter((e, i ,ar) => !(array.filter((e, i ,ar)=> i !== ar.indexOf(e)).includes(e)))
console.log(newArray) // output [1]
}
removeOccurences(["hello","hello","world",1,"world"])

Remove the last one array like [["1"]] by .splice() , why output = [[]] not []?

var arr=[["1"]];
arr[0].splice(0,1);
// arr = [[]]
Why I can't remove the last one array to blank ?
I need arr = [] not [[]] when removed and sub-array (array in array) is blank
Demo : http://jsbin.com/ehacof/1/edit
Edit : I just one to remove one by one like
var arr=[["1","2"],["1","2"]];
arr[0].splice(0,1);
arr[0].splice(0,1);
// arr = [[],["1","2"]];
I need arr = [["1","2"]];
Demo : http://jsbin.com/ehacof/9/edit
You are splicing on the first element on the array which is removing "1" from the internal array at arr[0]. This code should remove the first array, not the first element of the first array.
arr.splice(0, 1);
EDIT: If you want to remove that inner array if it's empty then you will need to check it like this.
arr[0].splice(0, 1);
if (arr[0].length === 0)
arr.splice(0, 1);
You removed the "1" from arr[0], so arr[0] is [] and arr contains now an empty array : [[]].
If you want to remove the array itself, splice arr, not arr[0]
var arr=[["1"]];
arr[0].splice(0,1);
if (arr[0].length === 0) {
arr.splice(0,1);
}
Array.splice removes some elements and returns them. Your array of arrays will still stay an array of arrays.
The JSON.stringify converts an empty array: [] to "[]" and thus an empty array of arrays: [[]] becomes "[[]]".
I added some more examples to your jsbin code to illustrate what your code actual does.
var arr=[["1"]];
var elem = arr[0].splice(0,1);
$("body").append(JSON.stringify(arr));
$("body").append(JSON.stringify(elem));
$("body").append(JSON.stringify([[]]));
You cannot use only splice to do the job, i could propose this:
Array.prototype.removeOne = function(i, j) {
if(this[i] == undefined) return this;
this[i].splice(j,1);
if (this[i].length == 0) this.splice(i,1);
return this;
};
Then use arr.removeOne(0,0)
First param is the main array index, the second param is the index of the subarray element to remove.
Edit: There is another way:
var arr=[["1"],["2"]];
arr[0].splice(0,1);
arr=arr.filter(function(ar){return ar.length});
try this in your demo ....
var arr=[["1"]];
arr.splice($.inArray(arr[0],arr));

Categories

Resources