Removing items from array in AngularJS - javascript

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.

Related

Looping through an array with conditions

I'm having a tough time figuring out how to loop through an array and if certain items do exist within the array, i'd like to perform a .slice(0, 16) to kind of filter an already existing array (lets call that existing array "routes").
For example, a previous process will yield the following array:
points = ['=00ECY20WA200_RECV_P1SEL',
'=00ECY20WA200_RECV_P2SEL',
'=00RECV_C1A_EINCSCMPP1',
'=00RECV_C1A_EINCSCMPP2',
'=00BYPS_C1A_EINCSCMP',
'=00ECY20WA200_BYPS_SPSL1',
'=00ECC92AG184YB01',
'=00ECC92AG185YB01',
'=00ECC92AG186YB01',
'=00ECC92AG187YB01',
]
So if any of the above items exist in the "points" Array, which in this case they all do (but in some cases it could just be 1 of the 10 items existing there), I'm trying to perform routes.slice(0, 16) to the other already existing array.
I've tried lots of different ways (for loops with if statements) and at this point I'm not sure if its my syntax or what, but I'm back at square 0 and I don't even have a competent piece of code to show for. Any direction would be greatly appreciated.
You could use a hash table for checking and filtering.
var points = ['=00ECY20WA200_RECV_P1SEL', '=00ECY20WA200_RECV_P2SEL', '=00RECV_C1A_EINCSCMPP1', '=00RECV_C1A_EINCSCMPP2', '=00BYPS_C1A_EINCSCMP', '=00ECY20WA200_BYPS_SPSL1', '=00ECC92AG184YB01', '=00ECC92AG185YB01', '=00ECC92AG186YB01', '=00ECC92AG187YB01'],
hash = Object.create(null),
filtered = points.filter(function (a) {
if (!hash[a.slice(0, 16)]) {
hash[a.slice(0, 16)] = true;
return true;
}
});
console.log(filtered);
ES6 with Set
var points = ['=00ECY20WA200_RECV_P1SEL', '=00ECY20WA200_RECV_P2SEL', '=00RECV_C1A_EINCSCMPP1', '=00RECV_C1A_EINCSCMPP2', '=00BYPS_C1A_EINCSCMP', '=00ECY20WA200_BYPS_SPSL1', '=00ECC92AG184YB01', '=00ECC92AG185YB01', '=00ECC92AG186YB01', '=00ECC92AG187YB01'],
pSet = new Set,
filtered = points.filter(a => !pSet.has(a.slice(0, 16)) && pSet.add(a.slice(0, 16)));
console.log(filtered);
EDIT: So it seems like you want to remove an element from an array called routes for each element in the points array. This is how you could do this:
function removeBrokenRoutes(brokenPoints, routes){
for(let pt of brokenPoints){
let index = routes.indexOf(pt);
if(index !== -1) routes.splice(index,1);
}
return routes;
}
Keep in mind that the larger the arrays, the more time this is going to take to complete.
You could use the filter and indexOf methods in combination:
var arr = [/* all the data you're checking against */];
var points = [/* the data you're checking for */];
var filteredArr = arr.filter(function(x) {
// will return -1 if the point is not found
return points.indexOf(x) !== -1;
});
filteredArr will contain all the points that appear in both arrays. The filter function works by taking a function with one argument x, which represents each item in the array. if the function returns true, the item will be added to the new array (filteredArr), and if false the function will move on to the next item. indexOf will check if the item is found in the other array. Also it is important to note that you will need a more complex solution (such as a hashtable) if the data set is very, very large as this is not necessarily the most performant method. But it's a good place to start as it is easy to understand.

Get first element in array with index not starting from 0

I'm using a javascript library which returns arrays not starting from zero like starting from 26 or 1500, what i want to do is a method to get the first element in that array regardless of the index number starting with 0 or any other number.
Are they any method to do this in javascript ?
I suggest to use Array#some. You get the first nonsparse element and the index. The iteration stops immediately if you return true in the callback:
var a = [, , 22, 33],
value,
index;
a.some(function (v, i) {
value = v;
index = i;
return true;
});
console.log(index, value);
The information below is generally useful, but for the problem the OP listed, Nina's answer is by far a better solution.
Those are called sparse arrays and they're one of the few situations where you may want to use for-in on an array.
Remember that arrays are objects in JavaScript, and array entries are properties keyed by names (array indexes) that meet certain criteria. So we can use the features that let us discover the properties on an object to find the indexes on your sparse array.
for-in example:
for (var n in theArray) {
if (theArray.hasOwnProperty(n) && isArrayIndex(n)) {
// Use theArray[n]
}
}
This answer shows how you can determine that n is an array index as opposed to being some other property. A very technical definition would be
function isArrayIndex(n) {
return /^0$|^[1-9]\d*$/.test(n) &&
n <= 4294967294;
}
...but a definition that's good enough for most of us would be
function isArrayIndex(n) {
return !isNaN(parseInt(n, 10));
}
Similarly, you can use Object.keys; since it only looks at own enumerable properties, you don't need the hasOwnProperty check:
Object.keys(theArray).forEach(function(n) {
if (isArrayIndex(n)) {
// ...
}
});
Note that officially, neither of those is in any particular order, not even in ES2015 ("ES6"). So in theory, you could see the indexes out of numeric order. In the real world, I've never seen an even vaguely-modern JavaScript engine that returned array indexes out of order. They're not required to, but every one I've tried does.
So officially, you would need to get a full list and then find the minimum value in it:
var min = Object.keys(theArray).reduce(function(min, n) {
var i = parseInt(n, 10);
return isNaN(i) || (min !== undefined && min > i) ? min : i;
}, undefined);
That'll given you undefined if the array is empty, or the min index if it isn't. But if you want to make the assumption you'll get the keys in numeric order:
// Makes an assumption that may not be true
var min = +Object.keys(theArray).filter(isArrayIndex)[0];
If you're using a JavaScript engine that's entirely up-to-date, you can rely on the order returned by Object.getOwnPropertyNames, which is required to list the array indexes in order.
var min = +Object.getOwnPropertyNames(theArray).filter(isArrayIndex)[0];
It may be useful to use a filter function on the array to get back a normalised array.
var fullArray = array.filter(function(n){
return n != undefined;
});
fullArray[0]
The answers here may help you decide Remove empty elements from an array in Javascript
I guess one alternative to Array.prototype.some() is the Array.prototype.findIndex() method. These are much faster than filter alone and will keep your array and indices untouched.
var arr = new Array(1000),
fi = -1;
arr[777] = 1453; // now we have a nice sparse array
fi = arr.findIndex(f => f !== void 0); // void 0 is the perfect undefined
console.log(fi);
console.log(arr[fi]);
With this piece of code you can find first assigned value index and then get the value from your array:
var a = [, , 22, 33];
var value = a.find((v, i) => i in a);
console.log(value);
/* ---------------------------------------------- */
var i = 0
while (!(i in a) && i < a.length) i++; // If i === a.length then the array is emtpy
console.info(i, a[i]);
First implementation uses Array.prototype.find which makes less variable usage so this is cleaner but to find the index you should call indexOf over the array.
But the second one is a little bit old fashioned but give the chance of having index without extra efforts.
BTW Nina's seems better. (can make it shorter?)
const arr = [0,1,2]
// using destructuring to get the first element
let [first] = arr
// plus: using destructuring to get the last element
let [first] = [...arr].reverse()

using underscore to compare two object lists and obtain the unique objects

We have 2 JavaScript object lists.
var AList = [{id:1,name:"AA"},{id:2,name:"BB"},{id:3,name:"CC"},{id:4,name:"DD"},{id:5,name:"EE"},{id:6,name:"FF"}]
var BList = [{id:1,name:"AA"},{id:2,name:"BB"},{id:3,name:"CC"},{id:4,name:"DD"}]
we need to eliminate the duplicates from both lists and return what is unique for AList. (id 5 and 6)
I've used a generic JavaScript implementation for this, but I like to implement a more sleek solution based on underscore.
for(var i=0;i<AList.length;i++){
for(var j=0;j<fBList.length;j++){
if(AList[i] && fBList[j] && (AList[i].id == BList[j].id)){
delete AList[i];
}
}
}
var uniqueList= _.uniq(AList);
After A list is done with deleting the duplicates, there are null elements in place where the duplicates were, therefore we needed to use _uniq to get a unique set of values.
_.difference(AList,BList)
Doesn't provide the answer.
You could combine the two arrays, then get the unique result.
var uniqueList = _.uniq(AList.concat(BList), function(item) {
return item.id;
});
Or you could use _.property(key):
var uniqueList = _.uniq(AList.concat(BList), _.property('id'));
Unfortunately _.difference does use strict equality, and there is no way to change that by a custom equality callback. You still need to compute it manually:
AList = _.uniq(AList, _.property('id'));
BList = _.uniq(BList, _.property('id'));
var bIds = _.pluck(BList, "id");
_.filter(AList, function(el) { return !_.contains(bIds, el.id); })
For those who stumble on this as I did, lodash now has a function called differenceWith which takes a comparator.
_.differenceWith(array, [values], [comparator])
https://lodash.com/docs#differenceWith

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

JavaScript, array.sort() two arrays based on only one of them

I just discovered array.sort() and saw that I can specify how to sort like this: (example taken from http://www.w3schools.com/jsref/jsref_sort.asp)
var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});
I've been doing my sorting manually just using Bubble Sort because the arrays are small, but I was wondering if array.sort() can be used in place of this:
// Sort rowCategories[i] by rowWidth[i]
swapped = true;
while (swapped) {
swapped = false;
for (var i = 0; i < rowCategories.length-1; i++) {
if (rowWidth[i] < rowWidth[i+1]) {
var swap = rowCategories[i];
rowCategories[i] = rowCategories[i+1];
rowCategories[i+1] = swap;
swap = rowWidth[i];
rowWidth[i] = rowWidth[i+1];
rowWidth[i+1] = swap;
swapped = true;
}
}
}
What would I write for the built in sort to do the equivalent work?
There is a way of multi sorting arrays but I like the array of objects better. Here is the multi sort:
function multisort(sortBy,otherArrays){
var keys=[],i,tmpKeys;
sortBy.sort(function(a,b){
var ret=(a>b)?1:(a<b)?-1:0;
// storing the return values to be used for the other arrays
keys.push(ret);
return ret;
});
for(i=0;i<otherArrays.length;i++){
// copy the stored retun values
tmpKeys=keys.concat([]);
otherArrays[i].sort(function(){
// return the saved values based on sortBy array's sort
return tmpKeys.splice(0,1);
});
}
}
var arr1=[1,2,3],
arr2=[5,6,7],
reverse=["c","b","a"];
multisort(reverse,[arr1,arr2])
console.log(arr1);
console.log(arr2);
console.log(reverse);
Sorting by object key:
var arr=[
{id:1,col1:3,col2:2},
{id:2,col1:2,col2:2},
{id:3,col1:1,col2:1}
];
function sortBy(arr,keys){
var i=0;
arr.sort(function(a,b){
var i=0;
while(a[keys[i]]===b[keys[i]]&&i<keys.length){
i++;
}
return (keys.length===i)?0:(a[keys[i]]>b[keys[i]])?1:-1;
});
}
//sort by col2 then col1
sortBy(arr,["col2","col1"]);
console.log(arr);
//sort by id
sortBy(arr,["id"]);
console.log(arr);
this only requires a little modification. Instead of storing two arrays store one array with an object with the two attributes. Then you can do something like this.
arr.sort(functiona(a,b){return a.rowWidth - b.rowWidth});
the object must contain the attributes rowWidth and rowCatagories
The built-in sort() can only sort one array at a time, and the comparison is based on the values, not the indexes.
What you're doing is similar to PHP's array_multisort() function. If you use load the php.js library, it includes an implementation of this function. The implementation is here.
Actually the vanilla the sort function uses depends on browser JS engine implementation, for instance Mozilla uses MergeSort I believe.
By default it compare array items as strings and if you need any other consideration you must pass your own compare function to sort and function must return negative, 0 or positive number indicating the items comparison result.
You can use this sort function instead of yours, that would be much faster.

Categories

Resources