Coz*_*ama 7 java sorting list comparator
我有一个点列表,其中每个点都是一个很小的size列表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);
});
Run Code Online (Sandbox Code Playgroud)
这是排序之前的输入:
(2, 1000)
(9, -1000)
(3, 15)
(9, -15)
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)
Run Code Online (Sandbox Code Playgroud)
这是使用上述比较器排序后产生的结果:
(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -10)
(10001, -8)
Run Code Online (Sandbox Code Playgroud)
观察结果:
x。(5, 12)之前已正确放置(5, 10)。(9, -15)之前已正确放置(9, -1000)。(10001, -10)是放在之前的(10001, -8)。尽管-8大于-10.感觉我错过了一些微不足道的东西。我尝试了一些其他编写比较器的方法,例如使用Integer.compare(a, b)或 just 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];
});
Run Code Online (Sandbox Code Playgroud)
排序前输入:
(2, 1000)
(9, -1000)
(3, 15)
(9, -150
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)
Run Code Online (Sandbox Code Playgroud)
排序后:
(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -8)
(10001, -10)
Run Code Online (Sandbox Code Playgroud)
因此,数组列表已正确排序,正如(10001, -8)之前正确放置的那样(10001, -10)。
我无法理解为什么改变点的表示解决了这个问题,因此解决了这个问题。如果需要,我可以提供有关如何创建点列表的更多详细信息。
我错过了一些微不足道的事情
equals()应该使用方法来进行对象比较。Double equals==检查两个引用是否指向内存中的同一对象。
如果您更改比较器内的条件,!a.get(0).equals(b.get(0))它将正常工作。
然而,(10001, -10)被放在(10001, -8)之前。即使-8大于-10。
出现这种行为的原因是JVM缓存了范围内的Integer(以及Byte、Short和)的所有实例。即这些实例被重用,假设值为 的自动装箱结果将始终是相同的对象。Long[-128; 127]int12
由于示例中的小值(例如3, 5, )12将由单个对象表示,因此对它们进行比较==没有问题。但是,与值为will 的==两个实例进行比较的结果是,因为在这种情况下,堆中将有两个不同的对象。Integer10001false
缓存常用对象的方法称为享元设计模式。它在Java中很少使用,因为当创建和销毁大量相同的对象时,这种模式可以带来好处。只有在这种情况下,缓存这些对象才能显着提高性能。据我所知,它用于游戏开发。
Point必须是一个对象,而不是一个列表,正如Code-Apprentice在他的回答中指出的那样。利用对象的力量,不要过度使用集合。它带来了几个优点:
注意:对象也可能被滥用,其中一个可能的指标是,一个类除了 getters 之外没有声明任何行为,并且它的数据正在该类外部的代码中以某种方式进行处理。
尽管点的概念(作为几何对象)并不复杂,但在方法方面有一些有用的选项。例如,您可以使该类的实例Point能够检查它们是否水平或垂直对齐,或者两个点是否在特定半径内。并且Point类可以实现Comparable接口,以便点能够在没有Comparator.
Java 8方法sort()
被添加到接口中List。它需要一个 的实例Comparator,并且如果列表的元素实现可比较,并且您希望它们根据自然顺序排序null可以作为参数传递。
如果指定的比较器为 null,则此列表中的所有元素都必须实现 Comparable 接口,并且应使用元素的自然排序。
因此,Collections您可以sort()直接在点列表上调用方法,而不是使用实用程序类(假设Point实现Comparable<Point>):
points.sort(null); // the same as points.sort(Comparator.naturalOrder());
Run Code Online (Sandbox Code Playgroud)
此外,您还可以使用default接口static中的方法Comparator(例如ComparisonInt()和thenComparing() )创建多个自定义比较器。
(有关如何使用Java 8方法构建比较器的更多信息,请查看本教程)
@Alexander Ivanchenko很好地解释了为什么你会看到你所做的行为。该问题的一种解决方案是使用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];
});
Run Code Online (Sandbox Code Playgroud)
除此之外,我建议创建一个Point类:
class Point {
public int x;
public int y;
}
Run Code Online (Sandbox Code Playgroud)
这里我使用public字段来遵循结构模式。如果您想添加 getter 和 setter 以及其他行为,请随意这样做。使用类来表示数据的结构使代码更易于理解且更易于维护。事实上,您可以轻松地Comparable在一个Point或一个Comparator<Point>类上实现。
| 归档时间: |
|
| 查看次数: |
368 次 |
| 最近记录: |