Java数组的排序列表和列表的排序列表

Java sorting list of array vs sorting list of list

我有一个点列表,其中每个都是一个很小的列表 2。我想按 x 的递增顺序对点列表进行排序,如果 x 值相等,我通过按 y.

的递减顺序排序来打破平局

我写了一个自定义比较器来对这些点进行排序:

Collections.sort(points, (a, b) -> {
    if (a.get(0) != b.get(0)) {
        return a.get(0) - b.get(0);
    } return b.get(1) - a.get(1); 
});

这是排序前的输入

(2, 1000)
(9, -1000)
(3, 15)
(9, -15)
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)

这是使用上述比较器排序后产生的结果

(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -10)
(10001, -8)

观察:

  1. 输入在 x 上按升序排序。
  2. (5, 12) 正确地放在 (5, 10) 之前。
  3. (9, -15) 正确地放在了 (9, -1000).
  4. 之前
  5. 然而,(10001, -10)被放在了(10001, -8)之前。即使 -8 大于 -10.

感觉好像遗漏了一些琐碎的东西。我尝试了其他几种编写比较器的方法,例如使用 Integer.compare(a, b)a.compareTo(t),但得到了相同的结果。

最后,我将点的表示形式从 List<Integer> 更改为 int[] 并再次编写了相同的比较器。查看以下结果:

Collections.sort(points, (a, b) -> {
    if (a[0] != b[0])
        return a[0] - b[0];
    return b[1] - a[1];
});

排序前输入:

(2, 1000)
(9, -1000)
(3, 15)
(9, -150
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)

排序后:

(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -8)
(10001, -10)

因此数组列表得到正确排序,因为 (10001, -8) 被正确地放在 (10001, -10) 之前。

我无法理解为什么更改点的表示可以解决问题,从而解决这个问题。如果需要,我可以提供有关如何创建点列表的更多详细信息。

I am missing something trivial

方法equals()应该用于对象比较。 Double equals == 检查两个引用是否指向内存中的同一个对象

如果您将比较器内部的条件更改为 !a.get(0).equals(b.get(0)),它将正常工作。

However, (10001, -10) was put before (10001, -8). Even though -8 is larger than -10.

这种行为的原因是 JVM 缓存了 Integer 的所有实例(以及 ByteShortLong) 在 [-128; 127] 范围内。 IE。这些实例被重用,假设 int 的值 12 的自动装箱结果将是 always 相同的对象。

因为您的示例中的小值,如 3512 将由 单个对象 表示,所以对它们进行了比较== 没有问题。但是对于两个值为 10001Integer 实例与 == 比较的结果将是 false 因为在这种情况下将是两个不同的对象中。

缓存常用对象的方法称为Flyweight design pattern。它很少在 Java 中使用,因为当 吨相同的对象 创建并且销毁。只有在这种情况下,缓存这些对象才能显着提高性能。据我所知,它用于游戏开发。

利用物体的力量

Point 必须是对象,而不是列表,如 has pointed out in his answer. Use the power of objects and don't 。它带来了几个 优点:

  • class为您提供结构,当您从对象的角度思考时,更容易组织您的代码;
  • 在 class 中声明的行为 可重用 并且更容易测试;
  • 有了classes,就可以发挥polymorphism的威力了。

警告: 对象也可能被滥用,其中一个可能的指标是 class 除了 getter 及其数据之外没有声明任何行为正在此 class.

之外的代码中以某种方式进行处理

虽然点的概念(作为一个几何对象)并不复杂,但有一些关于方法的有用选项。例如,您可以创建 Point class 的实例,以便能够检查它们是否对齐 水平垂直[=115] =],或者两个点是否在特定的 半径 内。 Point class 可以实现 Comparable 接口,这样点就可以在没有 Comparator.

的情况下进行自我比较

排序

Java8方法sort() 已添加到 List 界面。它需要一个 Comparator 的实例,如果列表的元素实现可比较,并且您希望它们根据自然顺序排序 null 可以作为参数传递。

If the specified comparator is null then all elements in this list must implement the Comparable interface and the elements' natural ordering should be used.

因此,您可以直接在点列表上调用方法 sort(),而不是使用实用程序 class Collections(假设 Point 实现了 Comparable<Point>) :

points.sort(null); // the same as   points.sort(Comparator.naturalOrder()); 

此外,您可以使用 Comparator 界面中的 defaultstatic 方法创建多个自定义比较器,例如 comparingInt() and thenComparing().

(有关如何使用 Java 8 方法构建比较器的更多信息,请查看 this tutorial)

很好地解释了为什么您会看到自己的行为。该问题的一种解决方案是使用 Integer.compareTo():

Collections.sort(points, (a, b) -> {
    int xCompare = a[0].compareTo(b[0];
    if (xCompare != 0) {
        return xCompare;
    }
    retirm a[1].compareTo(b[1];
});

除此之外,我建议创建一个 Point class:

class Point {
    public int x;
    public int y;
}

这里我使用 public 字段来遵循结构模式。如果您想添加 getter 和 setter 以及其他行为,请随意这样做。使用 class 来表示数据结构使代码更易于理解和维护。事实上,您可以轻松地在 PointComparator<Point> class.

上实现 Comparable