我已经实现了Apriori算法。它工作得很好,但我遇到了一个奇怪的问题:我已经定义了一个Rule类来维护生成的规则。
这是:
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));
}
知道问题出在哪里?
答案 0 :(得分:3)
使用HashSet
存储具有自定义equals
实现的类的对象时,您必须具有匹配的hashCode
自定义实现。
如果两个对象相等(根据自定义equals
实现), they must have the same
hashCode . In the code you posted, I don't see an overriding of
hashCode in the
Rule`类。
将实例添加到HashSet
时,hashCode
方法用于确定将在其中存储实例的哈希表中的索引。然后,迭代存储在此索引中的实例的链接列表,以查看该实例是否已存在。迭代该列表时,使用equals
。如果两个相等的对象由hashCode
映射到HashSet
中的不同索引,则不会检测到复制,因为它们将存储在单独的链接列表中。
这在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.
在hashCode
的Javadoc中:
* <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.
答案 1 :(得分:1)
你的hashCode()方法在哪里?这也很重要:)
答案 2 :(得分:1)
覆盖hashCode
时,您应始终覆盖equals
,反之亦然。
在您的Rule
课程中添加以下内容:
@Override
public int hashCode() {
return left.hashCode()
^ right.hashCode()
^ lookupArtist.hashCode();
}
Here是一个很好的答案,解释了为什么重写两者都很重要。
此外,您的equals方法可以写为
@Override
public boolean equals(Object another){
Rule rule = (Rule) another;
return left.equals(rule.left)
&& right.equals(rule.right)
&& lookupArtist.equals(rule.lookupArtist);
}
最后一句话:你对equals-implementation的另一种尝试不是对称的,即rule1.equals(rule2)
当{且仅当rule2.equals(rule1)
时不是这种情况。这违反了平等合同。