3

I'm using java objects like this:

public class GeoName {
   private String country;
   private String city;
   private float lat;
   private float lon;
}

I receive a List of GeoName and I would like to remove the duplicate cities in the same country that are in the list, as efficient as I could. I mean, if i receive the following list:

Madrid, Spain, ...
London, England, ...
Madrid, Mexico, ...
London, England, ...
Paris, France, ...
Madrid, Spain, ...

I would like to remove the repeated items (city+country) until the list was like this:

Madrid, Spain, ...
London, England, ...
Madrid, Mexico, ...
Paris, France, ...

I'm working on it but I don't know how to do it!

Any idea, please?

Thanks!

PS: I can't use a Set collection because I found the name of a city repeated in a country with different latitude and longitude (it's strange, but they exist). So it wouldn't be a complitely equal item on the Set

Ommadawn
  • 2,450
  • 3
  • 24
  • 48

4 Answers4

2

For removing duplicate entry from collection of custom data (e.g. GeoName ) implement the equals() and hashcode() methods.

Then add the data into a Set for removing duplicate entry.

Implement the equals() and hashcode() according to your logic to identify duplicate data.

1

You can implement hashCode() and equals() for GeoName that do only consider country and city.

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;

    GeoName geoName = (GeoName) o;

    if (!country.equals(geoName.country))
        return false;
    return city.equals(geoName.city);
}

@Override
public int hashCode() {
    int result = country.hashCode();
    result = 31 * result + city.hashCode();
    return result;
}

After that you can use a HashSet() to put all GeoNames in. Duplicates will be sorted out automatically and efficiently.

    List<GeoName> myInputList = ...;
    Set<GeoName> geoSet = new HashSet<>(myInputList);
A1m
  • 2,897
  • 2
  • 24
  • 39
1

This should do it:

I create your class with a modified .equals method and then check if 2 test instances of that class are the same using said .equals method.

class GeoName {
   private String country;
   private String city;

   public GeoName(String country, String city) {
       this.country = country;
       this.city = city;
   }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final GeoName other = (GeoName) obj;
        if (!Objects.equals(this.country, other.country)) {
            return false;
        }
        if (!Objects.equals(this.city, other.city)) {
            return false;
        }
        return true;
    }
}

Test class:

public class Cities {
    public static void main(String[] args) {
          // ArrayList<GeoName> geos = new ArrayList<>(); 

          GeoName test = new GeoName("Madrid", "Spain");
          GeoName test1 = new GeoName("Madrid", "Mexico");

            if (test.equals(test)) {
                System.out.println("True 1");
            }

            if (test.equals(test1)) {
                System.out.println("True 2");
            }
    }
}

Output:

True 1

You would then loop through the array and check all of them and if it doesnt exist then you add it to the array, I leave that to you.

Daedric
  • 502
  • 4
  • 23
  • You should not do it like this. You would have to compare each instance with another with equals, resulting in a `O(n^2)` complexity. Using HashSet is more general, cleaner and runs in `O(n)`. – A1m Jul 11 '17 at 19:33
  • Well it is fine for small scale. – Daedric Jul 11 '17 at 19:36
1

This is a complete example:

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class GeoName {
   private String country, city;
   private float lat, lon;

   public GeoName(String country, String city, float lat, float lon){
       this.country = country;
       this.city = city;
       this.lat = lat;
       this.lon = lon;
   }

   @Override
   public boolean equals(Object other){
      if(other==null) return false;
      if(other instanceof GeoName){
        return ((GeoName)other).city.equals(this.city) &&
               ((GeoName)other).country.equals(this.country);
      }
      return false;   
    }

    @Override
    public String toString(){
        return city + ", "+ country +
               ", " + lat +", " + lon;
    }


    @Override
    public int hashCode(){
       return Objects.hash(country, city);

    }

    // to test
    public static void main(String[] args) {
        List<GeoName> list = new ArrayList<>();

        list.add(new GeoName("Madrid", "Spain",1.0f, 2.0f));
        list.add(new GeoName("England", "London",3.0f, 4.0f));
        list.add(new GeoName("England", "London",3.0f, 4.0f));
        list.add(new GeoName("France", "Paris",7.0f, 9.0f));
        list.add(new GeoName("Mexico", "Madrid",9.0f, 10.0f));

        Set<GeoName> set = new HashSet<>(list);

        for(GeoName geoName : set){
            System.out.println(geoName);
        }          
    }    
}

Output:

London, England, 3.0, 4.0
Madrid, Mexico, 9.0, 10.0
Paris, France, 7.0, 9.0
Spain, Madrid, 1.0, 2.0
Yahya
  • 13,349
  • 6
  • 30
  • 42