Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java TreeSet: comparing and equality

I'd like to have list of object sorted with property 'sort_1'. But when I want to remove I'd like it to use property 'id'. The following code represents the problem.

package javaapplication1;

import java.util.TreeSet;

public class MyObj implements Comparable<MyObj> {
    public long sort_1;
    public long id;

    public MyObj(long sort, long id) {
        this.sort_1=sort;
        this.id=id;
    }

    @Override
    public int compareTo(MyObj other) {        
        int ret = Long.compare(sort_1, other.sort_1);               
        return ret;
    }    

    public String toString() {
        return id+":"+sort_1;
    }

    public static void main(String[] args) {
        TreeSet<MyObj> lst=new TreeSet<MyObj>();

                MyObj o1 = new MyObj(99,1);
        MyObj o2 = new MyObj(11,9);

        lst.add(o1);
        lst.add(o2);    

        System.out.println(lst);

                MyObj o3 = new MyObj(1234, 1);
                //remove myObje with id 1
                boolean remove=lst.remove(o3);

                System.out.println(lst);
    }

}

Output of this code is:

[9:11, 1:99]
[9:11, 1:99]

I need to have list sorted as I do a lot of additions to the list. I don't want to explicitly use any 'sort' method. What are my options ?

EDIT:

My requirement is to have: objects with 'id' as unique but there can be object's with duplicate 'sort' value.

like image 441
knocker_d Avatar asked Jun 10 '15 13:06

knocker_d


People also ask

How does the TreeSet test if two elements are equal?

"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".

Is TreeSet balanced Java?

The TreeSet uses a self-balancing binary search tree, more specifically a Red-Black tree. Simply put, being a self-balancing binary search tree, each node of the binary tree comprises of an extra bit, which is used to identify the color of the node which is either red or black.

Which of the following method does TreeSet use to determine order and equality?

It uses compare() (or compareTo()) method to determine the equality of two elements.

How do you compare two sets that are equal?

Equal and EquivalentTwo sets A and B are equal if they have exactly the same elements. We write A = B. Two sets A and B are equivalent if n(A)= n(B). Another way of saying this is that two sets are equivalent if they have the same number of elements.


1 Answers

Just by chance I found this out yesterday as well. This seems to be an artifact of the implementation of TreeMap (which is what TreeSet uses to store its entries).

TreeMap uses a binary search tree for storing the key/value pairs, but it only ever uses the given Comparator (or the compare function if the key class implements Comparable) to check for equality, as you can see in this code exxcerpt:

final Entry<K,V> getEntry(Object key) {
    // Offload comparator-based version for sake of performance
    if (comparator != null)
        return getEntryUsingComparator(key);
    if (key == null)
        throw new NullPointerException();
    @SuppressWarnings("unchecked")
        Comparable<? super K> k = (Comparable<? super K>) key;
    Entry<K,V> p = root;
    while (p != null) {
        int cmp = k.compareTo(p.key);
        if (cmp < 0)
            p = p.left;
        else if (cmp > 0)
            p = p.right;
        else
            return p;
    }
    return null;
}

I'd almost call this a (not really fixable) bug since the JavaDoc of the Comparable interface explicitly says that returning 0 with the compareTo function does not have to imply "equalness":

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)).

You won't be able to store stuff in the TreeSet the way you want it to. I'd recommend using a normal HashMap or a LinkedHashMap and then just sorting the output when you need to sort it with Collections.sort.

Besides all of this, I always find it strange to implement the Comparable interface. Most things don't really have a "natural" ordering that is immediately obvious. Sometimes this can lead to strange bugs (like this one!), so I typically always sort only when I need it using custom Comparators. Java 8 makes writing those really easy as well!

like image 98
mhlz Avatar answered Sep 28 '22 10:09

mhlz