Remove all elements from array of strings that do not contain "IN" - javascript

I need to remove all elements in an array that do not contain "IN" in uppercase exactly like that.
How I thought of doing this was to traverse the array with a for loop and write all values that contain IN to another array.
Is there a way I can do it without writing to a new array and just removing those items that don't match from the current array?
Here is the code for how I was planning on doing it:
arrTwo = [];
for(var i = 0; i<arr.length; i++){
if(arr[i].indexOf('IN') > -1) arrTwo.push[arr[i]];
}

You can use ES5 filter method:
arr = arr.filter(function(s){
return ~s.indexOf("IN");
});
And using ES6 arrow functions, it can be simplified to:
arr = arr.filter(s=>~s.indexOf("IN"));

Here's a really good thread that has a couple of ways to accomplish this. If you do not delete the element of the array in the correct manner, you that element will be undefined rather than actually deleted. The .spilce() method is what you want to look into.
Deleting array elements in JavaScript - delete vs splice

I would do it using the splice() method:
var testArray = [ 'this one contains IN', 'this one does not' ];
function filterArray ( arr ) {
var i = arr.length;
//-- Loop through the array in reverse order since we are modifying the array.
while (i--) {
if (arr[i].indexOf('IN') < 0) {
//-- splice will remove the non-matching element
arr.splice(i, 1);
}
}
}
filterArray( testArray );
document.body.innerText = JSON.stringify(testArray);
JSFiddle: http://jsfiddle.net/5DW8L/1/

Related

Remove a user id from array of ids [duplicate]

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

How can I remove duplicates elements between 2 arrays in angular?

Say I have
arr1 = ["Tom","Harry","Patrick"]
arr2 = ["Miguel","Harry","Patrick","Felipe","Mario","Tom"]
How can I remove the duplicate elements in arrays?
I want this output
arr2 = ["Miguel","Felipe","Mario"]
Use filter combined with includes. Example:
let arr1 = ["Tom","Harry","Patrick"]
let arr2 = ["Miguel","Harry","Patrick","Felipe","Mario","Tom"]
arr2 = arr2.filter(x=>!arr1.includes(x))
console.log(arr2)
I think that the best way will be to use filter() array method, iterate through the target array (it's arr2 in this case), and exclude duplicates via !arr1.includes(currentItem). This construction lets you know, does arr1 contain current item of iteration:
const arr1 = ["Tom","Harry","Patrick"];
const arr2 = ["Miguel","Harry","Patrick","Felipe","Mario","Tom"];
const result = arr2.filter(d => !arr1.includes(d));
console.log(result);
If you have lodash, you can use the difference function directly.
_.difference(arr2, arr1) will give the required output.
Edit: JSFiddle URL: https://jsfiddle.net/k3ynjq1m/3/
Using includes() is better because returns true or false, but unfortunately it is not supported by IE, see this. In case you want this working on IE too, you should use indexOf().
var arr1 = ["Tom","Harry","Patrick"]
var arr2 = ["Miguel","Harry","Patrick","Felipe","Mario","Tom"]
arr2 = arr2.filter(e=>arr1.indexOf(e)<0)
console.log(arr2)
And filter is better because:
The filter() method creates a new array with all elements that pass
the test implemented by the provided function.
Using regular js, you can use a nested for loop:
for (var i in arr2) {
var duplicate = false;
for (var i2 in arr1) {
if (arr2[i] == arr1.[i2]) {
duplicate = true;
}
}
if (duplicate) {
arr2.splice(i, 1);
}
}
I think you should keep a map and add elements to that map.
if element exists in map, then that is duplicate else add it to map.
The way you can store your duplicates is storing their value in another list. That is up to you.
Once you know your duplicates, duplicate it from the list.
This is O(n) complexity, and O(n) space complexity.
for(var i = 0 ; i<this.arr1.length; i++) {
for(var j = 0 ; j<this.arr2.length; j++) {
if(this.arr1[i] === this.arr2[j]) {
this.arr1.splice(i, 1);
this.arr2.splice(j, 1);
i--;
j--;
}
}
}
this.arr2 = this.arr1.concat(this.arr2);
console.log(this.arr2)
here's a working code (your exemple): https://stackblitz.com/edit/angular-yzte87
So the way I see it there are multiple ways to achieve what you're looking for,
Using filter and include like some mentioned above me -
It will work but I don't know how efficient that will be as you are using filter to iterate on arr2 and then for each element you iterate on arr1 to see if there's matching case, I don't know how familiar you are with algorithm analysis but it's O(N power 2) which is not very time efficient, means quickly as arr1 or arr2 will grow it will take much longer for your function to run, if you do go with that option please use sort() first so you might save time and be more efficient.
See Example:
let namesToRemove = ["Tom", "Harry", "Patrick"].sort()
let names = ["Miguel", "Harry", "Patrick", "Felipe", "Mario", "Tom"].sort()
let lastNameToRemove = namesToRemove[namesToRemove.length - 1]
names = names.filter((name) => {
if (name[0] > lastNameToRemove[0]) {
return true
}
return !namesToRemove.includes(name)
})
console.log(names)
Keep in mind that if you will use for loop and splice() you can just break and it will be even more efficient.
Using Map - You can iterate once on your first array and create a map in JS which is just using an object notation and once on your names array and check if there is a match, you can improve that using sort() and other improvement but the idea is, see below example.
See Example:
let namesToRemove = ["Tom", "Harry", "Patrick"]
let names = ["Miguel", "Harry", "Patrick", "Felipe", "Mario", "Tom"]
let namesToRemoveMap = {}
for (name of namesToRemove) {
namesToRemoveMap[name] = true
}
names = names.filter((name) => !namesToRemoveMap[name])
console.log(names)
Of course either way you choose I would include some more defensive checks, like if the arrays have value in them etc...
Hope I could explain myself clear, let me know if you need more help or if you have any question.
So you want to remove elements from an array (if they exist) based from another array.
Ok, let see... I have a component that implement a function with a similar logic:
let criteriaArr = ["Tom", "Harry", "Patrick"];
let arrToFilter = ["Miguel","Harry","Patrick","Felipe","Mario","Tom"];
let filteredArray = arrToFilter.filter(e => criteriaArr.indexOf(e) < 0);
console.log(filteredArray);
So what filter does is: Returns the elements of an array that meet the condition specified in a callback function.
what the callback function does is: for each element from arrToFilter, if that element does not exit in criteriaArr then keep it otherwise go to the next element.
Here is the function:
removeElems(arrToFilter: Array<any>): Array<any> {
let filteredArray = arrToFilter.filter(e => this._criteriaArr.indexOf(e) < 0);
return filteredArray;
}
this._criteriaArr is a private property with default value: private _criteriaArr = ["Tom","Harry","Patrick"]
Or, you can do it this way:
removeElems(arrToFilter: Array<any>, criteriaArr: Array<any>): Array<any> {
let filteredArray = arrToFilter.filter(e => criteriaArr.indexOf(e) < 0);
return filteredArray;
}
handle it with two array.
have fun ! :)

Javascript - Do something when an element in two arrays are the same?

I found a solution to where I get returned an array of elements without duplicates:
Array1 = Array1.filter(function(val) {
return Array2.indexOf(val) == -1;
});
However, I want to modify this code just a little bit. Instead of being returned an array without duplicates, I want to do something when there is a duplicate. The problem is, I'm not sure how exactly this code works. The thing is I'm not sure how val gets set, or what it even is.
for (var i = 0; i < json.length; i++) {
var item = json[i];
// if json.indexOf(val?), do something
}
Read the docs for the Array filter method then. The val parameter of the callback will be passed the single array items, i.e. json[i] or item in your case:
for (var i = 0; i < json.length; i++) {
var item = json[i];
if (json.indexOf(item) >= 0) {
// do something
}
}
var newArray = array1.filter(function(v, i) {
return array1.indexOf(v) == i;
});
This will return only unique itesm from array1;
array1.filter(function(v, i) {
// write your code here ('v' is individual value and 'i' is its index)
// don't return any anything if you don't want unique array to be returned.
// 'array1.indexOf(v) == i' checks if current value is duplicate from previous any values.
// try putting console.log on values you don't understand like (console.log(v,i) for values of 'v' and 'i')
return array1.indexOf(v) == i;
});
and off-curse you can loop an array with for loop as
for(i in array1){
// where i is index of array1, to get current value use array1[i]
if(array2.indexOf(array1[i]) >= 0){
// do something
}
console.log(i);
}
val is set by Array.prototype.filter, which calls the callback function on each element in the array. Since you don't want to filter you can use Array.prototype.forEach instead, which also calls the callback function once for each element in the array:
Array1.forEach(
// This function is called once per element in Array1
function(val){
if(Array2.indexOf(val) != -1){ // Check if that element is also in Array2
// `val` is in both arrays,
// Do something with it
}
}
);
You can utilize some modern libraries... like underscorejs.
Intersection is what you're looking for i guess: http://underscorejs.org/#intersection
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
So your code may be something like
if(_.insersection(arr1, arr2)){
//since [] array is Falsy in JS this will work as a charm
}
From MDN: indexOf
Returns the first index at which a given element can be found in the array, or -1 if it is not present.
From MDN: filter
Creates a new array with all elements that pass the test implemented by the provided function.
The first function works by returning true when an item from array1 isn't found in array2 (== -1). i.e.: Iterate through A and add anything not found in B.
So, to change to return only duplicates return true for anything that is found in both:
Array1 = Array1.filter(function(val) {
return Array2.indexOf(val) >= 0;
});
Array1 now contains only items with duplicates.

Array of functions cleanup of empty slots

im having a problem, i have a array of functions which is frequently added to and removed from.
But when i do a foreach on the array it says that the index don't exist.
Input:
arr[arr.length] = function () { Func() };
Remove:
delete arr[indexToRemove];
for don't work now so i use a foreach
for (key in arr)
I'm getting a feeling that it is possible to overflow on the index so to prevent this i would like to find empty array positions and reposition the items in it.
This is what I'm thinking for cleanup atm.
var temp = new Array();
var count = 0;
for (key in arr) {
if (arr[key] != null) {
temp[count] = arr[key];
count++;
}
}
arr = temp;
Is there a better solution and does a empty array of functions slot look like null?
Don't use a for...in loop to iterate over an array; use a standard counting for loop. Do use Array.push() instead of arr[arr.length] = cont to add new values. Also don't use delete to remove an element from an array; use Array.splice().
Input: arr.push(cont);
Remove: arr.splice(indexToRemove, 1);

Javascript / JQuery - How do I find the size of this array of objects?

I have this code to iterate through an array of objects:
for (vehicleIndex in scenes[sceneID].vehicles) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
...
}
but I need to know how to determine the number of items being iterated through so that on the final item, I can execute a particular function. How do I do this?
Example in ES5:
Object.keys( scenes[sceneID].vehicles ).forEach(function( vehicle, index, arr ) {
if( index === arr.length - 1 ) {
// do something on last entry
}
});
Even tho, "last" just means the last element which was looped over. Since there is specific order within a Javascript object (they are infact unordered). However, we could sort the object key names manually by just chaining a .sort() before the .forEach()
var arraySize = scenes[sceneID].vehicles.length;
var i;
var currentItem;
for (i = 0; i < arraySize; i++) {
currentItem = scenes[sceneID].vehicles[i];
if (i == arraySize - 1) {
// do something special
} else {
// do something not so special ;-)
}
}
scenes[sceneID].vehicles should have a length property.
for (vehicleIndex in scenes[sceneID].vehicles) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
...
}
doSomethingWithLastItem(vehicleId);
Because JS does not have block scope, by the time your loop finished vehicleId will be the last item's id.
In generic terms you can get the size of an array by accessing the .length property. You can also get the size of an object using Object.keys(obj).length.
Use this to find the length:
scenes[sceneID].vehicles.length
length is a built-in property in arrays. However, if you want to check for the last item, you have to check
scenes[sceneID].vehicles.length - 1
as arrays are zero-indexed.
Also, you should not use for...in to loop on arrays - if someone extends Array.prototype (or worse, Object.prototype), then you will not be happy. Use a normal for loop (which also allows you to use the final item easily):
var len = scenes[sceneID].vehicles.length;
for (var vehicleIndex = 0; vehicleIndex < len; vehicleIndex++) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
//...
}
//Do something with the final item here
//Similar to this: itemFunc(vehicleID);
See this SO question for more details.

Categories