Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove Duplicates from an Array of GeoFire Objects [duplicate]

I am working with Geofire and Firebase on Angular 6 to store locations and unfortunately it's storing a lot of duplicates this is an example (console logging my variable currentHits):

0: {location: Array(2), distance: "48.84", url: "assets/imgs/fix.png"}
1: {location: Array(2), distance: "48.84", url: "assets/imgs/fix.png"}
2: {location: Array(2), distance: "48.84", url: "assets/imgs/fix.png"}
3: {location: Array(2), distance: "48.85", url: "assets/imgs/free.png"}
4: {location: Array(2), distance: "48.85", url: "assets/imgs/free.png"}
5: {location: Array(2), distance: "48.85", url: "assets/imgs/free.png"}
6: {location: Array(2), distance: "48.87", url: "assets/imgs/low.png"}
7: {location: Array(2), distance: "48.87", url: "assets/imgs/low.png"}
8: {location: Array(2), distance: "48.87", url: "assets/imgs/low.png"}

Location basically is an array of latitude and longitude used to calculate distance, in id 0, 1 and 2 its the same coordinates, and 3,4 and 5 are also the same, ...

This is what I want to get:

0: {location: Array(2), distance: "48.84", url: "assets/imgs/fix.png"}
1: {location: Array(2), distance: "48.85", url: "assets/imgs/free.png"}
2: {location: Array(2), distance: "48.87", url: "assets/imgs/low.png"}

(Optional) this is how It stores these locations:

  ...
  hits = new BehaviorSubject([])

  ...
  queryHits(...){
 ....
 let hit = {
          location: location,
          distance: distance.toFixed(2),
          url:img
        }

        let currentHits = this.hits.value
        currentHits.push(hit)
        this.hits.next(currentHits)
....
}

It's true that this question has probably already been asked and I have been digging through all the similar questions and found these functions:

1. RemoveDuplicates()

function removeDuplicates(arr){
    let unique_array = []
    for(let i = 0;i < arr.length; i++){
        if(unique_array.indexOf(arr[i]) == -1){
            unique_array.push(arr[i])
        }
    }
    return unique_array
}

var newlist = removeDuplicates(list)

It didn't work I get the same list with duplicates.

2. arrUnique:

function arrUnique(arr) {
    var cleaned = [];
    arr.forEach(function(itm) {
        var unique = true;
        cleaned.forEach(function(itm2) {
            if (_.isEqual(itm, itm2)) unique = false;
        });
        if (unique)  cleaned.push(itm);
    });
    return cleaned;
}

var newlist= arrUnique(list);

Also, it didn't work..

3. onlyUnique

  onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
  }

var newlist = list.filter(onlyUnique)

Unfortunately it didn't work...

These are some of the answers given to similar problem to remove duplicates from an array and none of them worked. I don't understand why they won't work for my type of array, If anyone has an idea or knows why would be very helpful.

like image 412
Programmer Man Avatar asked Sep 24 '18 13:09

Programmer Man


People also ask

How to remove duplicates from an array of objects in JavaScript?

an array of objects? Method 2: Converting the array to a Set to remove the duplicates: A Set object holds only unique values of any type. This property can be used to store only the objects that are unique in the array. Each object of the array is first converted into a JSON encoded string using JSON.stringify method.

Is it possible to filter out duplicates from an array?

Mathew -> If it is simpler to prevent a duplicate object from being added to the array in the first place, instead of filtering it out later, yes, that would be fine too. @tonkatata This doesn't work with array of objects. How about with some es6 magic?

How do you remove duplicates from an ARR?

The 2nd entry in arr is a duplicate, and we want to remove it. To do this, we call arr.filter with a callback to check that the index of the item is the same as the index returned by findIndex . If they’re the same, then they’re the first instance of an object.

How to tell if the current item is a duplicate?

Since strings.indexOf (item) will always return the index of the first occurrence of the item, we can tell if the current item within the filter loop is a duplicate. If it is, we don't return it to the new array created by the filter () method


2 Answers

You could use a set to store and check for duplicate values.

const removeDuplicates = arr => {
    let matches = new Set();
    return arr.filter(elem => {
        const {distance} = elem;
        if(matches.has(distance)){
            return false;
        } else {
            matches.add(distance);
            return true;
        }
    })   
}

Bear in mind that using this approach you may remove results where the distance is the same but the co-ordinates differ. If that causes an issue for you then you'd need to also check against the lat/lng pair.

like image 181
Adam Avatar answered Oct 09 '22 01:10

Adam


Problem here is comparing Objects. Two objects are never equal unless both are referencing to same Object.

Example:

{} === {} // false

// Two objects are equal only if they are referencing to same object
var a = {};
a === a; // true

It is clear from your problem that you are facing the first case. Among the solutions you tested Solution 1 and Solution 3 are failing because of this reason as indexOf does === comparision.

But Solution 2 should have worked on your example as it does a deep comparision as explained here. https://lodash.com/docs#isEqual.

PS: It might be a simple typo i have observed in Solution 2 cleaned.,push(itm);, there is an extra comma. Hoping that is not the case I am moving ahead

So i guess the issue is inside your location array, if you can give the contents of location array we should be able to provide better solution. Or as others suggested you can filter based on a single key of the object like id or distance, instead of comparing the whole object

like image 27
AvcS Avatar answered Oct 08 '22 23:10

AvcS