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"])
I'm looking at an exercise and having trouble understand how the following works ( I'm trying to remove duplicates from an array)
var arr = ['a','b','c','a','b','d','e','f'];
var uniqueArray = arr.filter(function(item,pos){
return arr.indexOf(item) == pos;
});
My attempt to understand
Here item takes on all of our values in arr. Lets go through an iteration
First item = 'a' and pos = 0. Ok. now we want to only filter on the basis of if the index of 'a'is the same as 0
Here indexOf(a) == 0.
Great! this is true, lets put it in the new array.
Now lets move forward to where we see a again, namely at pos = 3
arr.indexOf(a) == 3
Wait... Doesent this meet our requirement as well? How does this even remove duplicates?
indexOf returns just one integer value, and it is the index of the first found item. So, when pos is 3 (and the item is a), indexOf will return 0 (because the first index of a is 0), 0==3 is false and the element will be removed.
Then, when the pos is 4 (and item is b), indexOf returns 2, the index of the first found b.
As for the objects, they can't have duplicate keys. Each new key will automatically overwrite the old one, so there won't be any duplicates.
Look:
var obj = {a:1, a:3, b:2,c:5,b:4};
console.log(obj)
nicael is right. indexOf(item) is just a function that goes through the array and looks for the first time item appears in the array, and returns the position in the array. In your example, if there is an a at 0 and a at index 3, then indexOf('a') will return position 0, while the value of pos is 3, so the filter returns false.
FOLLOW UP:
indexOf() has another parameter called the fromIndex, which lets you start the search from a position other than the beginning of the array. In this case, you can specify to skip over the first time 'a' occurs by doing arr.indexOf('a', 1) which starts the search at position 1, not 0. In this case the function would return true since the next 'a' is at position 3.
Can I use filter on an object?
No, because filter is a specific function of an Array object. You can get the keys of the object by doing a filter on Object.keys(myObject) since keys() returns an array.
Using your example:
var keyArray = Object.keys(myObject); //object can't have duplicate keys
keyArray.filter(function(item, index) {
return keyArray.indexOf(item) == index; //will never be false
});
Hashtable is the best way to eliminate the redundant values
Here is the code :
char arr[] = ['a','b','c','a','b','d','e','f'];
//it will contains all 26 places as zero (A - Z)
char hashArray[26]={0}
int i; //for iteration;
for(i=0;arr[i]!='\0';i++)
{
//it will subtracte the ascii value of the letter
//from 'a' so that we have the values from 0 to 26)
hashArray[arr[i]-'a']=arr[i];
}
for(i=0;i<26;i++)
{
if(hashArray[i]!=0) //to Ensure the positon has the character
{
printf("%c",hashArray[i]);
}
}
I don't know if it's a stupid question, but here it comes:
Imagine an array of unordered objects like:
[{id:4, name:"a"},{id:2, name:"b"},{id:3, name:"ee"},{id:1, name:"fe"},.....].
This array is dinamically created inside a loop using javascript, but, everytime I'll push something to the array I must check if an object with the same id exists and only pushs the newones.
Which one is faster:
1) At every loop check manualy the entire array.
or
2) Create a temporary unidimensional array only with ids and use indexOf to check if the new object id is present and then, if not present at the temporary array, add it to the original array.
How about
var a = []
var o = { id:10, name:"xyz" }
if(typeof a[o.id]=="undefined") {
a[o.id] = { name:o.name }
}
? That should be fastest for most machines. Or to not change your object structure
a[o.id] = { id:o.id, name:o.name }
But the better approach would be
function getA(i) { if (typeof a[i] == "undefined") return null;
return { id:i, name:a[i].name }; }
Let's say you have the follow array:
var array = ["app_angrybirds", "app_flappybird", "ilovebirds"];
How would you go about removing any array element that begins with the string "app_"?
for (var i = 0; i < array.length; i++) {
if(array[i].substr(0, 4) === "app_") {
array.splice(i, 1);
i--; //The index will be moved one forward at the end of the loop, but the whole array
//will be shifted, so we compensate by decrementing i
}
}
You can just loop through and check the first 4 characters (using substr) and compare it. If they match, remove the element using splice. We also use a small hack using i-- to keep the index pointing at the right place.
Explanation for the above:
The for loop steps through each element of the array. For each iteration, you compare the first four characters of the element,whose index matches with the iteration variable, to the string "app_". Here the array method substr(0,4) isolates the characters from the 0th element up to but not including the 4th element and makes the substring available for comparison with "app_".If the condition is true that the substring of the element matches with "app_" , use the splice() method to surgically remove the element from the array based on the parameters you pass to it, in this case the ith element.
This is the simplest way that I can think of:
var array = ["app_angrybirds", "app_flappybird", "ilovebirds"];
var result = array.filter(doesNotHave(/^app_/));
alert(JSON.stringify(result));
function doesNotHave(regex) {
return function (str) {
return !regex.test(str);
}
}
Hope that helps.
I have a Real-Time web app, receiving push events from Node JS, adding to and removing from an array in Javascript. I have found after doing the typical splice to remove the item by the matching value's index, the size of the array decreases as expected, but sometimes the element isn't getting removed.
My theory is the real time data is adding to and removing from the array in parallel for different places in the array, and sometimes the index position becomes out of date at the moment in time it's about to do the splice.
How can I remove an item from an array by value in real time if the index is always changing?
for(var i=0; i<data.geometries.length; i++) {
if(data.geometries[i].id == item.id) { //Found Item in Array
//do some stuff
data.geometries.splice(i,1); //Remove Geometry
break;
}
}
You could use .filter method:
var result = data.geometries.filter(function (e) {
return e.id !== item.id;
});
What you need is a sparse array, where you can have an array with gaps or holes. Using splice to modify the array will affect any indexes that come after the removed element. So, you could use a regular array as a sparse array, but you would delete items differently. For example:
// array to act as sparse array
var set = [1,2,3,4];
// remove an item by value
var pos = set.indexOf(3);
if (pos !== -1) {
// don't 'splice', just set to undefined
set[pos] = undefined;
}
// add an item
if (set.indexOf(5) == -1) {
set.push(5);
}
// to get the values from sparse array
var values = set.filter(function(v) { return typeof v !== 'undefined' });
console.log(values);
// => [1, 2, 4, 5]
This way, your indexes stay the same across parallel processes and threads.