Removing duplicates in array of objects [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Remove duplicates from an array of objects in javascript
var arr = [{empID:100,empName:greg},{empID:101,empName:Math},{empID:100,empName:greg}];
var sorted_arr = arr.sort(); // You can define the comparing function here.
// JS by default uses a crappy string compare.
var results = [];
for (var i = 0; i < arr.length - 1; i++) {
if (sorted_arr[i + 1].empID != sorted_arr[i].empID) {
results.push(sorted_arr[i]);
}
}
alert(results);
I have an array of objects, but when i try to remove the duplicate object which matches the ID, it does not get removed. What's the issue with the code.

Your code has two problems:
the sorting does not really work
you forget to add the last element to the result
I would suggest the following alternative:
var arr = ...;
arr.sort( function( a, b){ return a.empID - b.empID; } );
// delete all duplicates from the array
for( var i=0; i<arr.length-1; i++ ) {
if ( arr[i].empID == arr[i+1].empID ) {
delete arr[i];
}
}
// remove the "undefined entries"
arr = arr.filter( function( el ){ return (typeof el !== "undefined"); } );

Provided that empID is guaranteed to be a string or number, I would skip the sorting step and use an object as a hash of IDs that have already been seen:
var arr = [
{empID:100,empName:"greg"},
{empID:101,empName:Math},
{empID:100,empName:"greg"}
];
var results = [];
var idsSeen = {}, idSeenValue = {};
for (var i = 0, len = arr.length, id; i < len; ++i) {
id = arr[i].empID;
if (idsSeen[id] !== idSeenValue) {
results.push(arr[i]);
idsSeen[id] = idSeenValue;
}
}

Your sort function should really use a comparator, if you're going to be comparing items n and n+1
var sorted_arr = arr.sort(function(a,b) { return a.empID - b.empID; } );
This way you can be assured that sequential items in the list can possibly have duplicate empID properties.

Related

Loop over each element in Object Arrays [duplicate]

This question already has answers here:
Javascript equivalent of Python's zip function
(24 answers)
Closed 2 years ago.
I've an Object containing data that looks like this,
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
I was trying to loop over keys and get and first element in each key concate each element in each array, and join them together using , (my object has more keys that this ofc)
So the output should be like
val1,val3,val8
val2,val4,
,val5,
I tried to loop over keys and getting each value but i think i'm missing something in my loop, as i can't change the key if it found element in each object
These are my trials below.
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
for (let i = 0; i < obj[key].length; i++) {
console.log(obj[key][i])//This is always looping on the same key but different element
}
}
}
while i want it to be something close to
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(obj[key][i])
}
}
My solution uses a deep copy of the object and then a recursive array manipulation via shift():
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
var resObj = [];
function printByIndex(obj){
var newObj = JSON.parse(JSON.stringify(obj));
printByIndexHelper(newObj, 0);
}
function printByIndexHelper(obj, i){
var flag = false;
resObj[i] = [];
Object.keys(obj).forEach(function(key){
if(obj[key].length > 0){
resObj[i].push(obj[key].shift());
if(obj[key].length > 0){
flag = true;
}
}else{
resObj[i].push(null);
}
});
if(flag){
printByIndexHelper(obj, i+1);
}
}
printByIndex(obj);
console.log(resObj);
Maps over arrays and joins string. Math.max to get full length to iterate over. Uses flatMap to filter out unequal length array values.
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
const o = Object.values(obj)
const len = Math.max(...o.map(({length})=>length))
console.log(
Array(len).fill().map((x,i)=>o.flatMap(q=>q[i]||[]).join(','))
)
check this same output as u require
obj = {
Q1:['val1','val2'],
Q2:['val3','val4','val5'],
Q3:['val8']
}
var keys = Object.keys(obj);
var stack = [];
var maxLength = getMaxLength(obj);
for(var k = 0; k < 3;k ++) {
var arr = [];
for(var i = 0; i<keys.length;i++) {
const key = keys[i];
const elements = obj[key];
if(k < elements.length) {
arr.push(elements[k]);
}
}
console.log(arr+"\n");
//stack.push(arr);
}
function getMaxLength(jsonObj) {
var max;
var jsonKeys = Object.keys(jsonObj);
for(var key of jsonKeys) {
const arr = jsonObj[key];
if (max == null || arr.length > max) {
max = arr.length;
}
}
return max;
}

Jquery/Javascript removing entry from array with highest property value

I have a nice riddle that I would like to see solved. There might be a better way of doing this and i am open for idea's.
I am trying to write an undo function for a canvas drawing app.
I have the following object, within it an array with their own objects with three properties.
var allDamages= {};
allDamages['scratch'] = [];
allDamages['scratch'].push({"x":4,"y":6,"index":1});
allDamages['scratch'].push({"x":3,"y":3,"index":2});
allDamages['scratch'].push({"x":9,"y":9,"index":3});
allDamages['scratch'].push({"x":19,"y":39,"index":4});
allDamages['dent'] = [];
allDamages['dent'].push({"x":59,"y":69,"index":5});
allDamages['dent'].push({"x":59,"y":69,"index":9});
allDamages['dent'].push({"x":39,"y":19,"index":6});
allDamages['rip'] = [];
allDamages['rip'].push({"x":20,"y":22,"index":7});
allDamages['rip'].push({"x":100,"y":56,"index":8});
I want to remove the last entry from this array. I want to do this by the property 'index'.
So I need to somehow find the entry which has the highest value of the property 'index' and then remove it from the array. What is the best way in doing this?
Greetings,
Robert
allDamages.scratch.length -1 returns the last index for that array.
Edit:
allDamages.scratch.slice(-1).pop() returns the last array item.
And if you just want to remove the last item in your array you should (like Givi said) use the pop() method on a sorted array like so:
allDamages['scratch'].pop()
Edit2:
Because the question wasn't clear for me. This is my final shot at the problem.
var allDamagesInOneArray = [];
for(array in allDamages){
allDamagesInOneArray.concat(array);//Assuming every key is an array
}
allDamagesInOneArray.sort(function(a,b){
return a.index - b.index;
});
var lastObj = allDamagesInOneArray.slice(-1).pop(); //element with latest index
I think you should create an object that save three your properties. After that you create a stack for undo. Like this:
function yourObject(x,y,index){
this.x = x; this.y = y; this.index = index;
}
var yourStack = new Array();
yourStack.push(new yourObject(4, 6, 1));
If the highest index in an array is always the last element of the array:
allDamages.scratch = allDamages.scratch.slice(0, allDamages.scratch.length - 1);
This removes the last element of the array
If index is not incrementing or if you always want to remove the latest index, no matter in which of the damages arrays it is (as I'd guess) you can use this function:
var undo = function(input){
var max= 0;
var undoType = "";
var undoIndex = 0;
for( var type in input ) {
// type: string
var locations = input[type];
// locations: array
// find the location of the heighest index property.
for( var i = 0; i < locations.length; i++ ) {
if( locations[i]["index"] > max) {
max = locations[i]["index"] ;
undoType = type;
undoIndex = index;
}
}
}
var output = input[type].splice(undoIndex, 1);
return output;
}
This should remove the element with the largest "index" property from your damage array.
First off, store a counter for highest index property found in the objects, and the index of that object within the scratch array.
var highestIndex = -Infinity;
var indexInArray
Then if you're using jQuery:
$.each( allDamages.scratch, function highestIndex( index, object ){
if( object.index > highestIndex ){
highestIndex = object.index;
indexInArray = index;
}
} );
Or, if not:
for( var indexCounter = 0, indexCounter < allDamages.scratch, indexCounter++ ){
if( allDamanges.scratch[ indexCounter ].index > highestIndex ){
highestIndex = allDamages.scratch[ indexCounter ].index;
indexInArray = indexCounter;
}
};
Try:
var allDamages= {};
allDamages['scratch'] = [];
allDamages['scratch'].push({"x":4,"y":6,"index":1});
allDamages['scratch'].push({"x":3,"y":3,"index":2});
allDamages['scratch'].push({"x":9,"y":9,"index":3});
allDamages['scratch'].push({"x":19,"y":39,"index":4});
allDamages['dent'] = [];
allDamages['dent'].push({"x":59,"y":69,"index":5});
allDamages['dent'].push({"x":59,"y":69,"index":9});
allDamages['dent'].push({"x":39,"y":19,"index":6});
allDamages['rip'] = [];
allDamages['rip'].push({"x":20,"y":22,"index":7});
allDamages['rip'].push({"x":100,"y":56,"index":8});
var index;
var cnt = 0;
var val;
$.each(allDamages,function(k,v){
if(cnt == 0){
index = highest(v); //get highest value from each object of allDamages
val = k;
}
else{
if(highest(v) > index){
index = highest(v);
val = k;
}
}
cnt++;
});
console.log("highest : "+index+": "+val);
var len = allDamages[val].length;
for(var i=0;i<len;i++){
if(allDamages[val][i].index == index){
allDamages[val].splice(i,1); //remove object having highest value
break;
}
}
console.log(allDamages);
function highest(ary) {
var high = ary[0].index;
var len = ary.length;
if(len > 0){
for(var i=0;i<len;i++){
if(ary[i].index > high){
high = ary[i].index;
}
}
}
return high;
}
DEMO here.
I've simplified my array to:
allDamages.push({"x":39,"y":19,"index":6,"type":'dent'});
That way i can use .pop() function in a normal way.
Thank you all for the quick response!!!

Count how many strings in an array have duplicates in the same array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Array value count javascript
I have an array which contains several duplicates, what I'm trying to achieve is to count how many duplicates each unique string has in this one array.
The array looks something like this
array = ['aa','bb','cc','aa','ss','aa','bb'];
Thus I would like to do something like this
if (xWordOccurrences >= 5) {
// do something
}
But I'm not sure how I would code this.
I was thinking, create an object with each unique string, then loop through the original array, match each string with it's object and increment it's number by 1, then loop over the object to see which words had the most duplicates...
But this seems like an over complexe way to do it.
You can use an object which has keys of the Array's values and do something like this
// count everything
function getCounts(arr) {
var i = arr.length, // var to loop over
obj = {}; // obj to store results
while (i) obj[arr[--i]] = (obj[arr[i]] || 0) + 1; // count occurrences
return obj;
}
// get specific from everything
function getCount(word, arr) {
return getCounts(arr)[word] || 0;
}
getCount('aa', ['aa','bb','cc','aa','ss','aa','bb']);
// 3
If you only ever want to get one, then it'd be more a bit more efficient to use a modified version of getCounts which looks similar to getCount, I'll call it getCount2
function getCount2(word, arr) {
var i = arr.length, // var to loop over
j = 0; // number of hits
while (i) if (arr[--i] === word) ++j; // count occurance
return j;
}
getCount2('aa', ['aa','bb','cc','aa','ss','aa','bb']);
// 3
Try this function:
var countOccurrences = function(arr,value){
var len = arr.length;
var occur = 0;
for(var i=0;i<len;i++){
if(arr[i]===value){
occur++;
}
}
return occur;
}
var count = countOccurrences(['aaa','bbb','ccc','bbb','ddd'],'bbb'); //2
If you want, you can also add this function to the Array prototype:
Array.prototype.countOccurrences = function(value){
var len = this.length;
var occur = 0;
for(var i=0;i<len;i++){
if(this[i]===value){
occur++;
}
}
return occur;
}
How about you build an object with named property?
var array = ['aa','bb','cc','aa','ss','aa','bb'];
var summary = {};
var item = '';
for ( i in array){
item = array[i];
if(summary[item]){
summary[item] += 1;
}
else{
summary[item] = 1;
}
}
console.log( summary );
summary will contain like this
{aa: 3, bb: 2, cc: 1, ss: 1}
which you could then iterate on and then sort them later on if needed.
finally to get your count, you could use this summary['aa']
<script type="text/javascript">
var array = ['aa','bb','cc','aa','ss','aa','bb'];
var myMap = {};
for(i = 0; i < array.length; i++) {
var count = myMap[array[i]];
if(count != null) {
count++;
} else {
count = 1;
}
myMap[array[i]] = count;
}
// at this point in the script, the map now contains each unique array item and a count of its entries
</script>
Hope this solves your problem
var array = ['aa','bb','cc','aa','ss','aa','bb'];
var dups = {};
for (var i = 0, l = array.length; i < l; i++ ) {
dups[array[i]] = [];
}
for (str in dups) {
for (var i = 0, l = array.length; i < l; i++ ) {
if (str === array[i]) {
dups[str].push(str);
}
}
}
for (str in dups) {
console.log(str + ' has ' + (dups[str].length - 1) + ' duplicate(s)');
}
This function may do everything you need.
function countDupStr(arr, specifier) {
var count = {}, total = 0;
arr.forEach(function (v) {
count[v] = (count[v] || 0) + 1;
});
if(typeof specifier !== 'undefined') {
return count[specifier] - 1;
}
Object.keys(count).forEach(function (k) {
total += count[k] - 1;
});
return total;
}
Each value in the array is assigned and incremented to the count object. Whether or not a specifier was passed, the function will return duplicates of that specific string or the total number of duplicates. Note that this particular technique will only work on string-coercible values inside your arrays, as Javascript can only index objects by string.
What this means is that during object assignment, the keys will normalize down to strings and cannot be relied upon for uniqueness. That is to say, this function wouldn't be able to discern the difference between duplicates of 3 and '3'. To give an example, if I were to perform:
var o = {}, t = {};
o[t] = 1;
console.log(o);
The key used in place of t would eventually be t.toString(), thus resulting in the perhaps surprising object of {'[object Object]': 1}. Just something to keep in mind when working with Javascript properties.
I saw this post about it, perhaps it can help:
http://ryanbosinger.com/blog/2011/javascript-count-duplicates-in-an-array/

Remove duplicate element pairs from multidimensional array

I have an array that looks like this:
1. coordinates = [ [16.343345, 35.123523],
2. [14.325423, 34.632723],
3. [15.231512, 35.426914],
4. [16.343345, 35.123523],
5. [15.231512, 32.426914] ]
The latitude on line 5 is the same as on line 3, but they have different longitudes and are therefore not duplicates.
Both the latitude and longitude are the same on line 3 and 6, and are therefore duplicates and one should be removed.
The difficulty in this question that different arrays never compare equal even if they contain same values. Therefore direct comparison methods, like indexOf won't work.
The following pattern might be useful to solve this. Write a function (or use a built-in one) that converts arrays to scalar values and checks if these values are unique in a set.
uniq = function(items, key) {
var set = {};
return items.filter(function(item) {
var k = key ? key.apply(item) : item;
return k in set ? false : set[k] = true;
})
}
where key is a "hash" function that convert items (whatever they are) to comparable scalar values. In your particular example, it seems to be enough just to apply Array.join to arrays:
uniqueCoords = uniq(coordinates, [].join)
You can use standard javascript function splice for this.
for(var i = 0; i < coordinates.length; i++) {
for(var j = i + 1; j < coordinates.length; ) {
if(coordinates[i][0] == coordinates[j][0] && coordinates[i][1] == coordinates[j][1])
// Found the same. Remove it.
coordinates.splice(j, 1);
else
// No match. Go ahead.
j++;
}
}
However, if you have thousands of points it will work slowly, than you need to consider to sort values at first, then remove duplicates in one loop.
I rewrote the answer from thg435 (It does not allow me to post comments) and prototype it also using jQuery instead, so this will work on all browsers using it (Even IE7)
Array.prototype.uniq = function (key) {
var set = {};
return $.grep(this, function (item) {
var k = key
? key.apply(item)
: item;
return k in set
? false
: set[k] = true;
});
}
You can use it like:
arr = arr.uniq([].join);
If you are not on Safari this single liner could do the job
var arr = [[16.343345, 35.123523],
[14.325423, 34.632723],
[15.231512, 35.426914],
[16.343345, 35.123523],
[15.231512, 32.426914]],
lut = {},
red = arr.filter(a => lut[a] ? false : lut[a] = true);
document.write("<pre>" + JSON.stringify(red,null,2) + "</pre>");
It might be simpler to create another array keeping only unique coordinate pairs
var uniqueCoors = [];
var doneCoors = [];
for(var x = 0; x < coordinates.length; x++) {
var coorStr = coordinates[x].toString();
if(doneCoors.indexOf(coorStr) != -1) {
// coordinate already exist, ignore
continue;
}
doneCoors.push(coorStr);
uniqueCoors.push(coordinates[x]);
}
function sortCoordinates(arr){
var obj = {};
for(var i = 0, l = arr.length; i < l; i++){
var el = arr[i];
var lat = el[0];
var lng = el[1];
if(!obj[lat + lng]){
obj[lat + lng] = [lat, lng];
}
}
var out = [];
for(p in obj){
out.push([obj[p][0], obj[p][1]]);
}
return out;
}
I am not sure about coordinates[][] dataType. Make the comparison accordingly.
var dubJRows= new Array();
for(int i = 0; i < coordinates.length -2; i++){
for(int j = i+1; j < coordinates.length -1; j++){
if (i != j && chk_dubJRows_not_contains(j)) {
innerArray1 [1][1] = coordinates[i];
innerArray2 [1][1] = coordinates[j];
if ( innerArray1 [1][0] == innerArray2[1][0]
&& innerArray1[1][1] == innerArray2[1][1]) {
dubJRows.push(j);
}
}
}
}
//REMOVE ALL dubJRows from coordinates.

Create an array and check against it

I am not sure of how to do this, but what I want to do it create an array and be able to add new items to this array. Since the items are supposed to be a random number, when a new instance is created I would like it to be checked against the rest of the array and be sure that the number it has generated is not already in the array. How would I accomplish something like this?
I looked at Šime Vidas's answer and it seems to work, but I tried to shorten it to
var arr = [];
function add(a) {
var n = ~~(Math.random() * 100);
for (var i = 0; i < a.length; i++) {
if ( a[i] === n) { a.push(n) }
}
}
for (var i=0; i<5; i++){
add(arr)
}
document.getElementById('output').innerHTML += arr;
and I don't understand why this wouldn't work. It does pretty much the same thing, correct?
var arr = [];
function add(a) {
var n = ~~(Math.random() * 1000);
!is(a, n) && a.push(n);
}
function is(a, n) {
for (var i = 0; i < a.length; i++) {
if ( a[i] === n ) { return true; }
}
return false;
}
The add function creates a random integer number between 0 and 1000, and adds it to the array.
The is function checks whether the n number is somewhere inside the a array.
Demo: http://jsfiddle.net/kHhMp/2/
Demo 2: http://jsfiddle.net/kHhMp/3/
(Demo 2 shows that a number will only be added to the array if it's not already in it.)
btw
!is(a, n) && a.push(n);
is a short form of this:
if ( is(a, n) == false ) { a.push(n); }
The number is added to the array only if is(a, n) returns false.
UPDATE
var arr = [];
function add(a) {
var n = ~~(Math.random() * 1000),
ok = true;
for (var i = 0; i < a.length; i++) {
if ( a[i] === n ) { ok = false; }
}
ok && a.push(n);
}
If you enjoy fast code and you have many items in your array, you should use an Object rather than an Array.
Instead of doing var my_array=[]; my_array.push(my_number), use var my_object = {}; my_object[my_number] = true to add items in your structure.
With that approach, you can easily check if a new number is already in there with an if (my_object[my_number]) { /* already there */ } else { /* not there yet */ }
Once you're done, you can extract the list of numbers as an array by either using var keys = Object.keys(my_object), or if that's not available, var keys=[],i=0;for (keys[i++] in my_object);, more or less.
You may extend the built in Array object for your needs.
Array.prototype.pushUnique = function(value) {
var len = this.length;
for(var i = 0; i < len; i++) {
if(this[i]===value) return;
}
this.push(value);
}
var uniques = new Array();
uniques.pushUnique(1);
uniques.pushUnique(2);
uniques.pushUnique(1);
// array will contain only 1 and 2
The fastest, most cross-browser way is to iterate over the array using a loop:
var arr = [];
function addNum(num) {
for (i = 0, len = arr.length; i < len; i++) {
if ( arr[i] === num ) { return false; }
}
arr.push(num);
}
Be sure to get the length of the array before you run the loop so the length property isn't constantly checked.
var array = []
array[0] = 'Item'
array[0] === undefined
# returns false
array[1] === undefined
# returns true

Categories