2014-11-30 5 views
1

Я реализовал алгоритм Apriori. он работает очень хорошо, но у меня возникла странная проблема: я определил класс Rule для поддержания сгенерированных правил.custom equals() метод не работает должным образом

Здесь:

public class Rule 
{ 
    private Set<Integer> left; 
    private Set<Integer> right; 
    private LookupArtist lookupArtist; 

    public Rule(LookupArtist lookupArtist){ 
     left = new HashSet<>(); 
     right = new HashSet<>(); 
     this.lookupArtist = lookupArtist; 
    } 

    @Override 
    public boolean equals(Object another){ 
     Rule rule = (Rule) another; 

     if(this.left.equals(rule.getLeft()) && this.right.equals(rule.getRight())) 
      return true; 
     else 
      return false; 
    } 

    @Override 
    public String toString(){ 
     /* print the object */ 
    } 

    public void addToLeft(Integer toAdd){ 
     left.add(toAdd); 
    } 

    public void addToRight(Integer toAdd){ 
     right.add(toAdd); 
    } 

    public Set<Integer> getLeft(){ 
     return left; 
    } 

    public Set<Integer> getRight(){ 
     return right; 
    } 

} 

Я также реализован метод equals() по-другому, просто чтобы попробовать:

@Override 
    public boolean equals(Object another){ 
     Rule rule = (Rule) another; 
     boolean flag = true; 
     for(Integer artist : left){ 
      if(flag) 
      if(!rule.left.contains(artist)) 
       flag=false; 
     } 

     if(flag) 
      for(Integer artist : right){ 
       if(flag) 
       if(!rule.right.contains(artist)) 
        flag=false; 
      } 
     return flag; 

    } 

Объект LookupArtist используется для отображения чисел в некоторых строк.

Проблема в том, что когда я распечатываю правила, я обнаружил, что некоторые правила появляются два раза. Я также нашел в режиме отладки некоторые реплицированные правила, поэтому это не проблема печати. Правила сохраняются на карте:

static Map<Rule, Float> rules; 

. 
. 
. 

Rule rule = new Rule(lookupArtist); 
for(int j=0;j<i;j++){ 
    rule.addToLeft(a[j]); 
} 
for(int j=i;j<a.length;j++){ 
    rule.addToRight(a[j]); 
} 
if(!rules.containsKey(rule)){ 
    rules.put(rule, getRuleConfidence(rule)); 
} 

Любая идея, где проблема может быть?

ответ

1

Вы должны всегда переопределять hashCode при переопределении equals и наоборот.

Добавить что-то вроде этого, чтобы ваш Rule класс:

@Override 
public int hashCode() { 
    return left.hashCode() 
     ^right.hashCode() 
     ^lookupArtist.hashCode(); 
} 

Here хороший ответ, объясняя, почему это важно, чтобы отменить оба.

Кроме того, ваш метод равно можно записать в виде

@Override 
public boolean equals(Object another){ 
    Rule rule = (Rule) another; 
    return left.equals(rule.left) 
     && right.equals(rule.right) 
     && lookupArtist.equals(rule.lookupArtist); 
} 

последнее замечание: Ваша другая попытка Равных-реализации не является симметричным, т.е.это не тот случай rule1.equals(rule2) если и только если rule2.equals(rule1). Это нарушение договора равных.

+0

большое спасибо. не знал об этом :) –

+0

Добро пожаловать. – aioobe

3

При использовании HashSet для хранения объектов класса с пользовательской реализацией equals вы должны иметь соответствующую пользовательскую реализацию для hashCode.

Если два объекта равны (по обычаю equals реализации ), they must have the same хэш-код . In the code you posted, I don't see an overriding of хэш-код in the Rule` класс.

При добавлении экземпляра к HashSet, hashCode метод используется для определения индекса в хэш-таблице в котором экземпляр будет сохранен. Затем связанный список экземпляров, хранящихся в этом индексе, повторяется, чтобы увидеть, есть ли экземпляр уже там. При повторении этого списка используется equals. Если два одинаковых объекта отображаются на hashCode к разным индексам в HashSet, дублирование не будет обнаружено, поскольку они будут храниться в отдельных связанных списках.

Об этом говорится в Javadoc из equals:

* Note that it is generally necessary to override the <tt>hashCode</tt> 
* method whenever this method is overridden, so as to maintain the 
* general contract for the <tt>hashCode</tt> method, which states 
* that equal objects must have equal hash codes. 

И в Javadoc из hashCode:

* <li>If two objects are equal according to the <tt>equals(Object)</tt> 
*  method, then calling the <code>hashCode</code> method on each of 
*  the two objects must produce the same integer result. 
+0

спасибо я не это карты тоже рассмотрите hashcode: S –

1

И где ваш хэш-код() метод? Это также очень важно :)