Loop to remove an element in array with multiple occurrences - javascript

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"])

Related

add item to array in loop by this array js

I have the following method:
var items = [1,2,3];
$.map(items, function (item) {
if (item === 1) {
items.push(4);
}
console.log(item);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
and I expect in console 1,2,3,4, but see 1,2,3. I mean I want to see one extra loop item.
Can I resolve it somehow? And if yes, how can I resolve it?
Iterator methods, like .map() or .forEach(), will prevent visiting elements added during iteration by using only the original length.
To avoid that, you'll want to use a standard loop, such as for..of (with the default array iterator checking length as it progresses):
var items = [1, 2, 3];
for (var item of items) {
if (item === 1) {
items.push(4);
}
console.log(item);
}
Though, other types of loops can be used to do the same.
Of course, beyond this current example, be careful that the loop doesn't become infinite from there always being new elements to iterate to next.
Yes certainly you can resolve it, but in your specific case, items is passed by value to your map function so that you won't accidentally alter the original variable. The purpose of map is not for what you are using, but for mapping by specific key for an object or associative array. You should fall back to for loop or some other method for getting your desired output.
var items = [1, 2, 3];
for (var i = 0; i < items.length; i++) {
const item = items[i];
if (item === 1) {
items.push(4);
}
console.log(item);
};
use forIn instead of forOf, because sometime forOf give an error (maybe forOf not supported older version of js )..
var items = [1,2,3];
var k;
for (k in items){
if(items[k] === 1){
items.push(4);
}
}
alert(items);

Write a function that rotates an array using .pop and .splice

I need to write a function that takes two arguments. It will modify the array(are) by popping an element and splicing it at the start of the array. It should be repeated num times. My attempt so far:
function rotate(arr, num) {
var i = 0;
while (i<num){
arr.pop();
arr.splice(0, 0, arr.pop());
i++;
}
return arr;
}
console.log(rotate(["Harry","Sarah","Oscar","Tina"],2));
Array::pop() removes and returns the removed element. You need to use it only once.
As #Xufox correctly mentions
Usually this is done with arr.unshift(arr.pop()); I’m not sure why OP needs to use splice here…
function rotate(arr, num) {
var i = 0;
while (i<num){
arr.unshift(arr.pop());
i++;
}
return arr;
}
console.log(rotate(["Harry","Sarah","Oscar","Tina"],2));
popwill remove the last entry of your array and return it. When doing it twice, you loose an entry
function rotate(arr, num) {
var i = 0;
while (i<num){
var x = arr.pop();
arr.splice(0, 0, x);
i++;
}
return arr;
}
console.log(rotate(["Harry","Sarah","Oscar","Tina"],2));
Instead of telling us what the function does right now, would you explain in general terms what the function should do? Or what result do you expect from the array in the example?
I see a couple of things:
In line 4 you are using arr.pop(). This is removing one item from the array and not placing it anywhere. Therefore, your array has one less item.
You are calling arr.pop() one more time so you are removing yet one more item from the array.
Instead of splice(0,0...) you could use unshift(). This will add an item to the beginning of the array. (Oposite of push())
Do you really need to pass and argument that tells how many times should the array rotate? Could you use for your purposes the lenght of the array?
To achieve what you want, why you need pop() and loop, simply twice splice() is enough.
arr.splice(0,0, ...arr.splice(arr.length-num));
function rotate(arr, num) {
arr.splice(0,0, ...arr.splice(arr.length-num));
return arr;
}
var arr =["Harry","Sarah","Oscar","Tina"];
rotate(arr, 2);
console.log(arr);

Removing items from array in AngularJS

I have this two integers arrays:
I am working on my Angularjs tutorial project.
In controller I have this two arrays:
var arrA=[12,54,76,98,45];
var arrB=[12,98];
I need to delete from arrA all numbers that inside arrB.
arrA have to be like this after implementation:
arrA=[54,76,45]
What is best and elegantic way to implement it in angularjs?
You can use Array.prototype.filter() in conjunction with Array.prototype.indexOf()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
var arrA=[12,54,76,98,45];
var arrB=[12,98];
arrA = arrA.filter(function(o){
return arrB.indexOf(o) == -1;
});
document.write(JSON.stringify(arrA));
Off the top of my head.
//Run a loop to go through all elements in arrB
for (var i=0;i<arrB.length;i++) {
//keep position of element i in arrA
//if it's not there index will be equal to -1
var index=arrA.indexOf(arrB[i])
//if it is there
if(index!=-1) {
//remove 1 element at position index from arrA
arrA.splice(index,1)
}
}
Good luck.
This has nothing to do with angular btw, it's basic javascript.
Here's a fiddle:
https://jsfiddle.net/MichaelSel/t2dfg31c/
how about the following:
var result = arrA.filter(function(elem){
return arrB.indexOf(elem) === -1;
);
To delete items from any array you need to use splice:
$scope.items.splice(index, 1);
now what you can do is, you can run a for loop to identify the duplicate element. Once identified you can remove it using splice function.
Angular doesn't concern itself with things like array manipulation. JavaScript provides facilities for that though:
var diff = arrA.filter(function(item) {
return arrB.indexOf(item) < 0;
});
Fiddle
If arrB is very large, you might want to allow it to be O(N) (for smallish ones) up to O(N log N), instead of O(n^2):
var lookup = arrB.reduce(function(lookup, item) {
lookup[item] = true;
return lookup;
}, {});
diff = arrA.filter(function(item) {
return !Object.prototype.hasOwnProperty.call(lookup, item);
});
However, this only works if the string representation of the item is what you are looking at. It would work for integers.

How to find all combinations of elements in JavaScript array

I have the following array:
[[A,1,X],[B,2,Y],[C,3,Z]]
I want to be able to get all combinations of the first index of each sub array and then loop through those combinations performing a single task on each. So these are the combinations I'm after (Note I need the combination of the same value as well):
[[A,A],[A,B],[A,C],[B,A],[B,B],[B,C],[C,A],[C,B],[C,C]]
I'd then loop through that and do something with each of the values.
I'm not sure where even to start here so any advice or pointers would be really helpful!
You need to effectively loop through the array twice. Based on what you want you can just statically access the first element each time:
var arr = [['A',1,'X'],['B',2,'Y'],['C',3,'Z']];
var newArr = [];
var length = arr.length;
var curr;
for (var i = 0; i < length; i++) {
curr = arr[i][0];
for (var j = 0; j < length; j++) {
newArr.push([curr, arr[j][0]]);
}
}
console.log(newArr);
Fiddle
Try this:
var data = [['A',1,'X'],['B',2,'Y'],['C',3,'Z']];
function getCombinations(data) {
var combinations = [];
data.forEach(function(first) {
data.forEach(function(second) {
combinations.push([first[0], second[0]]);
});
});
return combinations;
}
console.log(getCombinations(data));
Here is the jsfiddle-demo
Let's decompose the problem. First, let's get extracting the first element of each subarray out of the way:
function get_elts(data, idx) {
return data.map(function(v) { return v[idx]; });
}
So
> get_elts(data, 0) // ['A', 'B', 'C']
Decomposing the problem like this is fundamental to good program design. We don't want to write things which jumble up multiple problems. In this case, the multiple problems are (1) getting the first element of each subarray and (2) finding the combinations. If we write one routine which mixes up the two problems, then we will never be able to re-use it for other things. If our boss comes and says now he wants to find all the combinations of the second element of each subarray, we'll have to cut and paste and create nearly duplicate code. Then we'll be maintaining that code for the rest of our lives or at least until we quit. The rule about factoring is do it sooner rather than later.
Then, create all combinations of any two arrays:
function combinations(arr1, arr2) { //create all combos of elts in 2 arrays by
return [].concat.apply( //concatenating and flattening
[], //(starting with an empty array)
arr1.map( //a list created from arr1
function(v1) { //by taking each elt and from it
return arr2.map( //creating a list from arr2
function(v2) { //by taking each element and from it
return [v1, v2]; //making a pair with the first elt
}
);
};
)
);
}
Normally we would write this more compactly. Let's walk through it:
Array#concat combines one or more things, or elements inside those things if they are arrays, into an array.
Function#apply lets us provide an array that will turn into the argument list of concat.
Array#map creates a parallel array to arr1, which contains...
elements which are two-element arrays based on looping over arr2.
Right, this is not your mother's JavaScript. It's almost a different language from the style where you initialize this and set that and loop over the other thing and return something else. By adopting this style, we end up with code which is more precise, concise, reusable, provably correct, future-friendly, and maybe optimizable.
By future-friendly, I mean among other things ES6-friendly. The above could be rewritten as:
combinations = (arr1, arr2) => [].concat(...arr1.map(v1 => arr2.map(v2 => [v1, v2])));
Get ready guys and girls, this will come up in your job interviews pretty soon now. Time to move on from jQuery.
Now the problem can be expressed as:
var first_elts = get_elts(data, 0);
combinations(first_elts, first_elts);

javascript does not splice all the element of the array

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.

Categories

Resources