Java 按(x,y)坐标和偏移量排序会违反比较器契约
我试图对x和y点的集合进行排序,在x上有一个偏移量,这样当p.x==q.x或ABS(p.x-q.x)Java 按(x,y)坐标和偏移量排序会违反比较器契约,java,sorting,collections,coordinate-systems,Java,Sorting,Collections,Coordinate Systems,我试图对x和y点的集合进行排序,在x上有一个偏移量,这样当p.x==q.x或ABS(p.x-q.x)(10,10)>(20,0)>(0,20)。(还有,拼写为“及物性”。) 通常,compare、compareTo和equals方法不应使用公差,因为公差本质上是不及物性的。两个都低于公差的差异加起来可能等于高于公差的差异。所以我又做了一些测试,我相信发现了您的问题:溢出 我将您的比较方法变得非常简单,但仍然会出现以下错误: public int compare(ExtractPojo p, Ex
private static class XYOrder implements Comparator<ExtractPojo> {
public int compare(ExtractPojo p, ExtractPojo q) {
Integer a=p.x.intValue();
Integer b=q.x.intValue();
Integer c=p.y.intValue();
Integer d=q.y.intValue();
int offset=Math.abs(a-b); //calculate offset from x
if(offset < 15 || a == b) //if x is the same, sort by y coordinate
return c-d;
else return a-b; //if x is not same sort by x coordinate
}
}
我有一种感觉,我违反了一个短暂性规则,因为我已经在这个网站上广泛搜索了一个答案,但我不确定如何测试我在这里遗漏了什么
我在没有偏移量的情况下测试了这段代码,但没有得到这个错误消息,所以我知道这与我如何实现偏移量有关。几周来,我一直在努力解决这个问题,但运气不佳
我希望得到一些关于这方面的提示或建议。多谢各位
所以我能想到的唯一解决办法是首先按x位置排序,然后遍历每个x,根据偏移量调整x,使其相同,然后再按上面提到的x,y进行排序,没有偏移量。这样做看起来像是一种黑客行为,但我以前从未使用过比较器,我很难解决这个问题。再次检查您的代码。这就是Java文档关于
compare()
方法实现的内容
比较器c对一组元素S施加的顺序称为与equals一致,当且仅当c.compare(e1,e2)==0具有与e1相同的布尔值。S中的每个e1和e2都具有equals(e2)
您是否为
ExtractPojo
类重写了equals()
方法?你可以找到医生
另外,您不应该使用像a==b
这样的代码。这里有Integer
类型的变量。因此,它将只检查这两个变量是否指向同一个对象(在本例中,可能为false。更多信息)。使用a.equals(b)代替
我有一种感觉,我违反了瞬变性规则
你确实是。在您的比较器下,我们有(0,20)>(10,10)>(20,0)>(0,20)
。(还有,拼写为“及物性”。)
通常,
compare
、compareTo
和equals
方法不应使用公差,因为公差本质上是不及物性的。两个都低于公差的差异加起来可能等于高于公差的差异。所以我又做了一些测试,我相信发现了您的问题:溢出
我将您的比较方法变得非常简单,但仍然会出现以下错误:
public int compare(ExtractPojo p, ExtractPojo q) {
Integer x1 = p.x.intValue();
Integer x2 = q.x.intValue();
return x1 - x2;
}
这是因为在某些情况下,x1-x2会导致违反传递性的溢出。要检查此问题,请执行以下操作:
public int compare(ExtractPojo p, ExtractPojo q) {
Integer x1 = p.x.intValue();
Integer x2 = q.x.intValue();
checkSubtractionOverflow(x1, x2);
return x1 - x2;
}
//This will throw an exception if there is an overflow
public static void checkSubtractionOverflow(int left, int right) {
Math.subtractExact(left, right);
}
如果您看到异常:
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.subtractExact(Unknown Source)
然后您就知道您有需要解决的溢出问题。基本上,您的代码是这样说的:
- 如果x坐标彼此在15个单位内,则使用y坐标进行比较
- 如果x坐标彼此相差15个或更多单位,则使用x坐标进行比较
- x坐标是相等的,因此可以在不影响当前问题的情况下移动到任意一侧
- P.x在Q.x和P
- Q.x在R.x和Q
- P.x从R.x开始超过15个单位,P>R(因为P.x>R.x)
- Q.x在R.x和Q
另外,您正在使用
.intValue()
调用执行一些不必要的装箱/拆箱操作整数a=P.x
是一个整数对整数的赋值。如果(偏移量<15 | | a==b)
:a==b
表示偏移量
为0,它包含在<15
的条件中。给出一些这种失败的例子,我不能给出一个失败的例子,因为我正在分析大量文件,这就是为什么很难看到它在哪里爆炸。@VinceEmighmergeHi
不是由OP…user1803551实现的方法,如果我只使用条件if(offset<15)和remove(a==b),我还是遇到了同样的问题。我会尝试一下,不,我不是压倒一切的平等者。我会让你知道这是怎么回事。即使我只是使用原语而不是对象整数,它仍然会失败。你是否重写了equals()
方法?对于您得到的异常,我能想到的可能原因是您的equals()
方法和比较器的compare()
方法中的相等概念不一致。例如,考虑代码< > < <代码>等于<代码> b>代码>(例如1000)。根据compare()
方法的逻辑,它应该返回0
(这意味着2个ExtractPojo
对象是相等的)。但是由于您没有重写equals()
方法,它将使用默认的equals()
方法由对象
类提供,当且仅当两个变量a
和b
引用同一对象时,此方法才返回true。确定。。用重写的equals()
检查它。不工作:/user2357112指出的问题,我想你必须找到一个解决方案。user2357112,很抱歉拼写错误。你对我如何解决这个问题有什么建议吗?@Mac:选择一个不同的排序标准,避免比较到一个容差。可以将x值分组到存储箱中,并按存储箱进行比较。
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.subtractExact(Unknown Source)