简体   繁体   中英

problem while removing an element from the TreeSet

I am doing the following

class RuleObject implements Comparable{



    @Override
    public String toString() {
        return "RuleObject [colIndex=" + colIndex + ", probability="
                + probability + ", rowIndex=" + rowIndex + ", rule=" + rule
                + "]";
    }
    String rule;
    double probability;
    int rowIndex;

    int colIndex;

    public RuleObject(String rule, double probability) {
        this.rule = rule;
        this.probability = probability;
    }
    @Override
    public int compareTo(Object o) {

        RuleObject ruleObj = (RuleObject)o;
        System.out.println(ruleObj);
        System.out.println("---------------");
        System.out.println(this);
        if(ruleObj.probability > probability)
            return 1;
        else if(ruleObj.probability < probability)
            return -1;
        else{
            if(ruleObj.colIndex == this.colIndex && ruleObj.rowIndex == this.rowIndex && ruleObj.probability == this.probability && ruleObj.rule.equals(this.rule))
                return 0;
        }
        return 1;

    }


}

And I have a TreeSet containing elements of RuleObject. I am trying to do the following :

System.out.println(sortedHeap.size());
        RuleObject ruleObj = sortedHeap.first();
        sortedHeap.remove(ruleObj);
System.out.println(sortedHeap.size());

I can see that the size of set remains same. I am not able to understand why is it not being deleted. Also while deleting I could see compareTo method is called. But it is called for only 3 object whereas in set there are 8 objects. Thanks

As polygenelubricants indicated, you must implement equals on your RuleObject s.

Moreover, your comparator is essentially broken. It does not impose total ordering , ie in certain cases it will claim that a RuleObject a is both greater than and less than another RuleObject b (eg if a.probability == b.probability and a.colIndex != b.colIndex .) This will result in unwanted behaviour during tree insertion, traversal etc.

In the end, compareTo must also be consistent with equals , ie

The natural ordering for a class C is said to be consistent with equals if and only if (e1.compareTo((Object)e2) == 0) has the same boolean value as e1.equals((Object)e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

If you do not care about RuleObject s ordering, use a HashSet .

Otherwise (ie you want to iterate over the TreeSet in a well defined, eg priority, order), implement Comparable to take into account all fields of interest, eg:

public int compareTo(Object o) {
  RuleObject r = (RuleObject)o;
  // assume no nulls for now, but you should eventually check
  // also assume o is always of type RuleObject for now,
  //  but you should eventually check
  return
    priority < r.priority ? -1 :
    priority > r.priority ? 1 :
    colIndex < r.colIndex ? -1 :
    colIndex > r.colIndex ? 1 :
    rowIndex < r.rowIndex ? -1 :
    rowIndex > r.rowIndex ? 1 : 0;
}

boolean equals(Object o) {
  // Delegate to compareTo(); no code duplication, consistent.
  return compareTo(o) == 0;
}

Look at the specification for remove :

Removes the specified element from this set if it is present. More formally, removes an element e such that (o==null ? e==null : o.equals(e)) , if this set contains such an element.

Your problem is that RuleObject does not @Override equals(Object other) . You need to do that, and of course, with that you also need to @Override hashCode() .


Also, the reason why compareTo is being called fewer times than the number of elements is because it's supposed to be a O(log N) operation; that's the whole purpose of using TreeSet . If you have 1024 elements, you can expect compareTo to be called no more than 10 times.


As Vlad points out, your comparator is broken. Specifically, the last statement return 1; breaks it. You should expand the equal probability case to return -1, 0, +1 depending on the other fields.

If you want it to Just Work™, try Apache's CompareToBuilder , HashCodeBuilder , and EqualsBuilder . I have provided sample code to start from below. You certainly don't have to take this route, but I think you will find it simplifies things. Note the consistent pattern between the different functions.

public int compareTo(Object o) {
  RuleObject ruleObj = (RuleObject) o;
  return new CompareToBuilder()
    .append(this.probability, ruleObj.probability)
    .append(this.colIndex, ruleObj.colIndex)
    .append(this.rowIndex, ruleObj.rowIndex)
    .append(this.rule, ruleObj.rule)
    .toComparison();
}

public int hashCode() {
  // You should customize the hard-coded numbers, as described in the docs.
  return new HashCodeBuilder(17, 37).
    append(probability).
    append(colIndex).
    append(rowIndex).
    append(rule).
    toHashCode();
}

public boolean equals(Object obj) {
  if (obj == null) { return false; }
  if (obj == this) { return true; }
  if (obj.getClass() != getClass()) {
    return false;
  }
  RuleObject rhs = (RuleObject) obj;
  return new EqualsBuilder()
    .append(probability, rhs.probability)
    .append(colIndex, rhs.colIndex)
    .append(colIndex, rhs.colIndex)
    .append(rule, rhs.rule)
    .isEquals();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM