在Java中,使用自定义比较器对大量ArrayList进行排序有时会引发iIllegalArgumentException

在Java中,使用自定义比较器对大量ArrayList进行排序有时会引发iIllegalArgumentException,java,opencv,Java,Opencv,我使用以下算法对8k+元素列表进行排序 //sort by y coordinates using the topleft point of every contour's bounding box Collections.sort(contourList, new Comparator<MatOfPoint>() { @Override public int compare(MatOfPoint o1, MatOfPoint o2) { Rect r

我使用以下算法对8k+元素列表进行排序

//sort by y coordinates using the topleft point of every contour's bounding box
Collections.sort(contourList, new Comparator<MatOfPoint>() {
    @Override
    public int compare(MatOfPoint o1, MatOfPoint o2) {
        Rect rect1 = Imgproc.boundingRect(o1);
        Rect rect2 = Imgproc.boundingRect(o2);
        int result = Double.compare(rect1.tl().y, rect2.tl().y);
        return result;
    }
} );


//sort by x coordinates
Collections.sort(contourList, new Comparator<MatOfPoint>() {
    @Override
    public int compare(MatOfPoint o1, MatOfPoint o2) {
        Rect rect1 = Imgproc.boundingRect(o1);
        Rect rect2 = Imgproc.boundingRect(o2);
        int result = 0;
        double total = rect1.tl().y/rect2.tl().y;
        if (total>=0.9 && total<=1.4 ){
            result = Double.compare(rect1.tl().x, rect2.tl().x);
        }
        return result;
    }
});
。我修改了算法,添加了以下内容以打印调试信息:

DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
log.debug("tot: {}; p1.x: {}, p1.y: {}; p2.x {}, p2.y {}",
        df.format(total),
        rect1.tl().x,
        rect1.tl().y,
        rect2.tl().x,
        rect2.tl().y);
,以下是例外occours之前的最后10个条目:

tot: 0,85; p1.x: 81.0, p1.y: 1415.0; p2.x 429.0, p2.y 1657.0
tot: 0,78; p1.x: 81.0, p1.y: 1415.0; p2.x 677.0, p2.y 1820.0
tot: 0,75; p1.x: 81.0, p1.y: 1415.0; p2.x 703.0, p2.y 1879.0
tot: 0,78; p1.x: 81.0, p1.y: 1415.0; p2.x 1010.0, p2.y 1820.0
tot: 0,83; p1.x: 81.0, p1.y: 1415.0; p2.x 1250.0, p2.y 1708.0
tot: 0,85; p1.x: 81.0, p1.y: 1415.0; p2.x 1260.0, p2.y 1657.0
tot: 0,76; p1.x: 81.0, p1.y: 1415.0; p2.x 1282.0, p2.y 1867.0
tot: 0,82; p1.x: 81.0, p1.y: 1415.0; p2.x 1282.0, p2.y 1736.0
tot: 0,86; p1.x: 81.0, p1.y: 1415.0; p2.x 1282.0, p2.y 1649.0
tot: 0,76; p1.x: 81.0, p1.y: 1415.0; p2.x 1507.0, p2.y 1864.0
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(TimSort.java:777)
    at java.util.TimSort.mergeAt(TimSort.java:514)
    at java.util.TimSort.mergeCollapse(TimSort.java:441)
    at java.util.TimSort.sort(TimSort.java:245)
    at java.util.Arrays.sort(Arrays.java:1512)
    at java.util.ArrayList.sort(ArrayList.java:1462)
    at java.util.Collections.sort(Collections.java:175)
我从来没有遇到过这样的问题,有人能提供一个解释和解决方案,使这些算法可靠吗

提前非常感谢您的努力

里卡多

Edit1:我添加了调试信息,如下所示:

static Comparator<MatOfPoint> contourXComparator() {

    return new Comparator<MatOfPoint>() {
        @Override
        public int compare(MatOfPoint o1, MatOfPoint o2) {
            Rect rect1 = boundingRect(o1);
            Rect rect2 = boundingRect(o2);
            int result = 0;
            double total = rect1.tl().y / rect2.tl().y;
            /* debug purpose */
            DecimalFormat df = new DecimalFormat();
            df.setMaximumFractionDigits(2);
            log.debug("tot: {}; p1.x: {}, p1.y: {}; p2.x {}, p2.y {}",
                    df.format(total),
                    rect1.tl().x,
                    rect1.tl().y,
                    rect2.tl().x,
                    rect2.tl().y);
            /* endof debug purpose */
            if (total >= 0.9 && total <= 1.4) {
                result = Double.compare(rect1.tl().x, rect2.tl().x);
            }
            return result;
        }
    };
静态比较器轮廓比较器(){
返回新的比较器(){
@凌驾
公共整数比较(点o1,点o2){
Rect rect1=boundingRect(o1);
Rect rect2=边界Rect(o2);
int结果=0;
双倍合计=rect1.tl().y/rect2.tl().y;
/*调试目的*/
DecimalFormat df=新的DecimalFormat();
df.setMaximumFractionDigits(2);
log.debug(“tot:{};p1.x:{},p1.y:{};p2.x{},p2.y{}”,
df.格式(总计),
rect1.tl().x,
rect1.tl().y,
rect2.tl().x,
rect2.tl().y);
/*结束调试目的*/

如果(总数>0.9和总数<P>),第二个比较器不是及物的。考虑三个元素

  • a=(1,4)
  • b=(1,5)
  • c=(1,6)
(x,y)表示其边界矩形的尺寸


根据你的比较器
a
b
但是
a=c
。从那里你可以推断出
a=c
,但同时
a=c>b
。你不能按照这样的顺序排序,因此会出现异常。

你会一致地返回一个值进行比较。例如,如果你为b返回-1无论是A>B还是B>A,排序算法都无法工作

代码的主要问题是您引入了一个if块,它违反了比较,因为您可能有一组坐标,您可以通过返回0来调用它们,即使它们不是相等的


您可以尝试先排序,就像对y排序一样,然后进行筛选。

您在哪里添加了此打印功能?在方法的开头或结尾附近?@Mark我编辑了这篇文章以回复您抱歉,我认为我没有正确解释。让我试着重新措辞。
static Comparator<MatOfPoint> contourXComparator() {

    return new Comparator<MatOfPoint>() {
        @Override
        public int compare(MatOfPoint o1, MatOfPoint o2) {
            Rect rect1 = boundingRect(o1);
            Rect rect2 = boundingRect(o2);
            int result = 0;
            double total = rect1.tl().y / rect2.tl().y;
            /* debug purpose */
            DecimalFormat df = new DecimalFormat();
            df.setMaximumFractionDigits(2);
            log.debug("tot: {}; p1.x: {}, p1.y: {}; p2.x {}, p2.y {}",
                    df.format(total),
                    rect1.tl().x,
                    rect1.tl().y,
                    rect2.tl().x,
                    rect2.tl().y);
            /* endof debug purpose */
            if (total >= 0.9 && total <= 1.4) {
                result = Double.compare(rect1.tl().x, rect2.tl().x);
            }
            return result;
        }
    };