'Unique comparable points at Java TreeSet

Having a very simple example of Java code:

import java.util.*;

class Point implements Comparable<Point>{
  
   float x, y;
   
   Point(float x_, float y_) { x = x_; y = y_; }
   
   int compareTo(Point p_) { println(dist(x, y, p_.x, p_.y)); return dist(x, y, p_.x, p_.y) < 1E-4 ? -1 : 1; }  
    
   float dist(float x0_, float y0_, float x1_, float y1_) { return sqrt(pow(x1_ - x0_, 2) + pow(y1_ - y0_, 2)); }
  
}

public static void main(String[] args){

   TreeSet<Point> tp = new TreeSet<Point>();
   
   tp.add(new Point(0.125, 0.5));
   tp.add(new Point(0.-125, 0.25));
   tp.add(new Point(0.15, -0.75));
   tp.add(new Point(0.125, 0.5));
   
   System.out.println(tp);

}

And I've thought that every point would be unique, while there is a distance checking and if it's below epsilon code should remove duplicate.

But it's not work right keeping the fourth entry despite the fact that it is a duplicate of the first entry.

My intention is to get a set of unique points (vectors).



Solution 1:[1]

This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html

In other words, The TreeSet class does not maintain the uniqueness of its elements via the equals method but with the compareTo method of the class implementation, if the class implements Comparable, or with the compareTo of the given Comparator.

As others have pointed out in the comments, if you want to maintain uniqueness among your Points by their coordinates, you should override the equals and hashCode methods, as the general hashcode contract states and utilize a HashSet to store your Points.

In the following snippet, I've updated your class by implementing the equals, hashCode and toString methods to show how only three elements are printed instead of four.

public class Point implements Comparable<Point> {

    double x, y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    // ... your implementation ...

    @Override
    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (obj == this) return true;
        if (obj.getClass() != getClass()) return false;
        Point other = (Point) obj;
        return x == other.x && y == other.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }

    @Override
    public String toString() {
        return String.format("(%g;%g)", x, y);
    }

    public static void main(String[] args) {
        HashSet<Point> tp = new HashSet<>();

        tp.add(new Point(0.125, 0.5));
        tp.add(new Point(0. - 125, 0.25));
        tp.add(new Point(0.15, -0.75));
        tp.add(new Point(0.125, 0.5));
        
        System.out.println(tp);
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dan