How to efficiently remove the duplicate valued object from an array? - javascript

To simplify my question, suppose the objects are jqlite objects, using the angular.equals function, I can check whether they are equal. My question is: How do we use this function to remove duplicate item from an array of jqLite objects?
Here is what I tried:
// Suppose jqArr is the array stated above:
var result = [];
angular.forEach(jqArr, function(v_i){
if(result.length === 0){
result.push(v_i);
} else {
var isPushed = false;
angular.forEach(result, function(v_j){
if(angualr.equals(v_i, v_j)){
isPushed = true;
}
});
if(isPushed === false){
result.push(v_i);
}
}
})
console.log(result);
Suppose jqArr = [e_1, e_2, e_3, e_1, e_2], where e_i(s) are jQLite elements.
output should be:
[e_1, e_2, e_3]
*Please answer using only javascript and angularJs.

You can use ES6 Set like so:
let arr = [1,1,2,2,2,3,4,5,6,6,6,6,6];
let uniq = [...new Set(arr)];
The uniq array will contain unique values. If the aray is filled with object references, it will naturally work too.

In a more abstract form, you are performing an O(n^2) algorithm (same with indexOf and Set) but you can reduce the complexity to O(nlogn) by adding all the elements to the list without checks, after all the elements have been collected remove the duplicates be sorting (needs only one pass over the array to remove duplicates after sort).
This solution works only if you can store all the duplicates, for a "duplication factor" above 100% this is not efficient.
If you cannot perform a logic sort, hash function can give the same result.

Related

How to remove objects with the same key and value pair in arrays

I've looked through many stack overflow questions, but none seem to quite answer my question. I have an array of objects, which I would like to reduce by deleting all objects where the key and value are the same.
So my array of objects would be:
[{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}]
The end result should be:
[{a:1},{a:2},{c:3},{b:1},{c:4}]
I've tried using filer and map, but I can only get the first object in the array, rather than all the objects that have different key/value pairs in the array. I've also tried using filter and findIndex, but with the same problem.
I also can't filter the objects before pushing them into the array.
Can someone point me in the right direction?
You can compare the two items using JSON.stringify(). We then add to a new array using reduce, if it is in the array we don't add it otherwise we do add it.
const array = [{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}]
let unique = array.reduce((res, itm) => {
// Test if the item is already in the new array
let result = res.find(item => JSON.stringify(item) == JSON.stringify(itm))
// If not lets add it
if(!result) return res.concat(itm)
// If it is just return what we already have
return res
}, [])
console.log(unique)
Alternatively you could use a Set (as Fissure King metions) to make a unique list of items like this:
const array = [{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}]
let unique = [...new Set(array.map(itm => JSON.stringify(itm)))].map(i => JSON.parse(i))
console.log(unique)
Assuming that all your object are of different types(different properites) and are not complex in nature i.e., not nested objects..
Create a array list(which will act as multi dimensional array).
let uniqueArr = [];
Loop through your array which contains duplicates with Arr.forEach();
Get property of the object using
Object.getPropertyNames(item);
Check wether this type of object type already exists in your uniqueArr ,if not add the property type.
uniqueArr.push({property:[]});
If the property already exists in the uniqueArr, check whether the current property value exits in the property array inside uniqueArr.
If the property doesn't not exist add the new property to the respective property array.if the property exits skip and run the loop for next object.
Once loop completed, create resultArr with the help of the
uniqueArr.
Sample : uniqueArr [ {a:[1,2]}, {b:[1]}, {c:[3]} ];
var a = [{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}];
var newData = [];
a.map(ele=>JSON.stringify(ele)).forEach(ele=>{
if(newData.indexOf(ele) === -1){
newData.push(ele)
}
});
newData.map(ele=>JSON.parse(ele))
console.log(newData);

add and remove specific array elements using array.splice()

Is it possible to add to a specific part of an array, and then deleting a specific part of the array, in this case the end value using arr.splice()?
i currently do this like so:
var arr = [1,2,3,4,5,6,7,8,9];
arr.splice(0,0,"test");
which should return:
"test",1,2,3,4,5,6,7,8,9
i then do:
arr.pop();
which should return:
"test",1,2,3,4,5,6,7,8
I was wondering if it's possible to do this via the arr.splice() method or if there is any cleaner method to do the same, as potentially i'll be doing this a few times, so i would end up with something like:
arr.splice(0,0,"test");
arr.pop();
arr.splice(1,0,"test2");
arr.pop();
looking at the array.splice documentation it suggests i can only delete the element in the position i'm putting the new element into, not a different one.
In answer to my original question as confirmed in the comments. It is not possible to provide a separate index to insert and another to remove in an array using the splice method or potentially any other single statement in javascript. The best approach to try to achieve this in a single statement if i really needed it would be to create your own function, which really seems counter productive for the most part.
You can use Array.from() to set the .length and values of specific indexes of an array in a single call
var arr = [1,2,3,4,5,6,7,8,9];
arr = Array.from({length:arr.length - 1, ...arr, 0:"test"});
console.log(arr);
To achieve the pattern described at Question you can alternatively use a loop and Object.assign()
var arr = [1,2,3,4,5,6,7,8,9];
var n = 0;
var prop = "test";
while (arr.length > 1) {
Object.assign(arr, {length:arr.length -1,...arr, [n]:!n ? prop : prop+n});
++n;
console.log(arr);
}

I want to remove duplicate Object using javascript/jquery. is it possible easily?

I have created one array of object, and I want to insert Unique objects.
var a=[];
a.push(new Number(11));
a.push({aa:"asdf",bb:"sadf"}
a.push({aa:"asdf",bb:"sadf"}
JSON.stringify(a)
"[11,{"aa":"asdf","bb":"sadf"},{"aa":"asdf","bb":"sadf"}]"
I want result like
JSON.stringify(a)
"[11,{"aa":"asdf","bb":"sadf"}]"
var uniqueArray=[] is your resultArray. Array.indexOf is used to find whether the element already exist in the uniqueArray, if not simply push to uniqueArray, otherwise its a duplicate no need to push, resultant will be uniqueArray:
var uniqueArray=[]; //result array of contains duplicate free elements
for(var i=0;i<a.length;i++){
//to check for duplication in the result array
if(uniqueArray.indexOf(a[i])<0)
uniqueArray.push(a[i]);
}
return uniqueArray;

jquery exclude array elements

I have an array of elements which I want to maintain efficiently, adding and removing arrays of elements over time.
var myElements = $('.initial');
jquery's merge() seems perfect for adding items as it doesn't create a new array and just adds to the existing one:
$.merge(myElements, $('.to-add'));
Is there an equivalent for removing, that also modifies the array in-place? Something like:
$.exclude(myElements, $('.to-remove'));
I do actually have arrays of DOM elements, and the selectors are just used as examples.
Assuming that you're after the relative complement of b in a.
And you don't want to create additional objects while process.
The function is for both plain Array and jQuery set.
(thus used $.each, $.inArray instead of Array.prototype.forEach Array.prototype.indexOf)
I wrote a function that fits your requirement.
$.exclude = function(a,b) {
var idx;
$.each(b, function(i, val) {
while((idx = $.inArray(val, a)) !== -1) {
a.splice(idx, 1);
}
})
return a;
}
test this code here
https://jsfiddle.net/happyhj/uwd4L1dm/8/
and you can use like this.
$.exclude(myElements, $('.to-remove'));
use jquery not method,
var filtered = $(myElements).not($('.to-remove'));
You can use delete to remove an element from an array and then use $.grep to remove the empty space.
//[0] since $("#id") will be a jquery Object
//[0] will return the particular DOM element
var orgArray = [$("#merge1")[0],$("#merge2")[0],$("#merge3")[0]];
var secArray = [$("#merge4")[0],$("#merge5")[0]]
// Will merge other two values;
// jQuery merge will merge contents of
//two array into first array
var merArray = $.merge(secArray, orgArray);
// Want to remove $("#merge2");
var getIndex = merArray.indexOf($("#merge2")[0]);
if(getIndex >-1){
delete merArray[getIndex]
}
// length before filtering
$("#l1").text(merArray.length);
//Now will remove Empty Space
merArray = $.grep(merArray,function(n){
return n==0 || n
});
$("#l2").text(merArray.length);
JSFIDDLE
You are using methods that are meant for array literals. jQuery already has method add() which will return a modified jQuery object that includes the elements matching the selector
var myElements = $('.initial');
var newCollection = myElements.add('.to-add');
newCollection.not('.to-remove').doSomething();
Don't think of jQuery objects as arrays although they are array like.
Reference add()
It's not clear what your overall objective really is but most likely you can manage it with any number of filtering methods that already exist within the api

finding whether a value exists in a javascript object with jquery

I am trying to determine whether a object contains a specific value so that I can be sure not append the value I am looking for more than once and prevent recursion.
I have tried lots of methods but can't get any of them to work:
data = [
{val:'xxx',txt:'yyy'},
{val:'yyy',txt:'aaa'},
{val:'bbb',txt:'ccc'}
];
console.log(jQuery.grep(data, function(obj){
return obj.txt === "ccc";
}));
$.map(data, function(el) {
if(el.txt === 'ccc')
console.log('found')
});
Can this be done with map() grep() or inArray() or do I really have to loop through the entire array looking for the value ??
data is an array containing multiple objects, so you'll need to specify the index of the array you wish to look in:
data[0].val === 'xxx';
data[1].val === 'yyy';
data[2].txt === 'ccc';
As an update to your function, what's wrong with $.each? You're looping anyway with map or grep, so you may as well just be honest about it :P You can loop with for as well, but I'm exampling with $.each as it's almost identical to your current code.
$.each(data, function(el) {
if(el.txt === 'ccc')
console.log('found')
});
You will have to iterate the whole array as it's an array of objects, and comparing objects is done by the references not by the values.
for (var i = 0; i < data.length; i++){
if (data[i].val == 'something')
doSomething();
}
var stExist=$.inArray(reqelement, dataArray)
If you wish to avoid all this calculations yourself, there is a utility plugin underscore.js, which has lots of helper.
One of the helpers you are looking for http://underscorejs.org/#contains.

Categories