当前位置: 首页 > 知识库问答 >
问题:

Java, 使用自定义比较器对庞大的 ArrayList 进行排序有时会抛出 iIllegalArgumentException [重复]

钱均
2023-03-14

我使用以下算法对 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;
    }
});

问题是,虽然按Y坐标排序(第一个比较器)不会产生任何问题(我不知道这是否只是运气问题),

按X坐标(第二个比较器)排序会提示此异常:

java.lang.IllegalArgumentException: Comparison method violates its general contract!

.我修改了算法,添加了以下内容来打印调试信息:

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);

,这些是异常发生前的最后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)

我从来没有遇到过这样的问题,有人能提供一个解释和解决方案,让这些算法变得可靠吗?

预先非常感谢你的努力

里卡尔多

编辑1:我添加了如下调试信息:

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;
        }
    };

共有2个答案

傅博瀚
2023-03-14

您一致地返回一个值进行比较。例如,如果您为两个A返回-1

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

您可以先尝试排序,就像对 y 所做的那样,然后再过滤掉。

印曜灿
2023-03-14

您的第二个比较器不是传递的。考虑三个要素

    < li>a = (1,4) < li>b = (1,5) < li>c = (1,6)

(x,y)表示它们的边界矩形的尺寸。

根据您的比较器a

 类似资料:
  • 如何使用Comparator对对象的ArrayList进行正确排序,然后将排序后的数组传递给自定义数组适配器? 我试过这样做: ArrayList的内容类: 比较器: 在OnCreate中设置适配器: ...因为我使用的是定制的ArrayAdapter,就像: 我需要如何修改此适配器以使其与其他适配器一起工作? 谢谢你的帮助。

  • 问题内容: 我正在为我的通讯录应用程序实现排序功能。 我想排序一个。是一个包含四个字段的类:姓名,家庭电话,手机号码和地址。我想继续。 如何编写自定义排序功能来做到这一点? 问题答案: 这是有关订购对象的教程: Java教程-集合-对象排序 尽管我会举一些例子,但我还是建议你阅读它。 有多种排序方式。如果要定义自然的(默认)排序,则需要让实现。假设你想默认在上进行排序name,然后执行(为简单起见

  • 我有以下清单: 这是我的比较器函数: 我正在尝试使用它排序如下: 我不明白为什么第一个NaN不在列表的末尾。 我对升序排序列表的预期输出是: 我对降序排序列表的预期输出是: 在升序排序和降序排序的情况下,我希望NaNs在最后。 我知道sortwith使我们能够编写自己的比较器。有人能帮我吗?

  • 我需要测试的地方 有人能告诉我如何使用main中的getCompByName()按名称对ArrayList进行排序吗?我对比较器很陌生,对它们的用法很难理解。该方法返回一个比较器,所以我不确定这将如何实现。我知道我需要使用getCompByName()来排序,我只是不知道如何实现它。

  • 我有一个用类填充的树集。我想让这些按其继承排序,否则,只按其名称的字母顺序(以创建一个恒定的顺序)。但是由于某种原因,如果添加的类的顺序不正确,就会导致类的顺序不正确。 这是我的比较器: 下面是一个测试失败的例子: 排序集的实际值: 我的期望更像是: 我在调试时确实注意到,并非每个项目都相互比较。

  • 问题内容: 我想为汽车清单开发一个排序演示。我正在使用数据表显示汽车列表。现在实际上我想按汽车颜色对列表进行排序。这里不是按字母顺序排序的。我想使用我的自定义排序顺序,例如先是红色汽车,然后是蓝色,等等。 为此,我尝试使用,但它只允许按字母顺序排序。 因此,任何人都可以指导我实现使用该技术的方法,以便使排序变得更快。 问题答案: 我建议你为汽车颜色创建一个枚举,而不要使用字符串,并且枚举的自然顺序