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)
观察:
- 输入在
x
上按升序排序。
(5, 12)
正确地放在 (5, 10)
之前。
(9, -15)
正确地放在了 (9, -1000)
. 之前
- 然而,
(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
的所有实例(以及 Byte
、Short
和 Long
) 在 [-128; 127]
范围内。 IE。这些实例被重用,假设 int
的值 12
的自动装箱结果将是 always 相同的对象。
因为您的示例中的小值,如 3
、5
、12
将由 单个对象 表示,所以对它们进行了比较==
没有问题。但是对于两个值为 10001
的 Integer
实例与 ==
比较的结果将是 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
界面中的 default
和 static
方法创建多个自定义比较器,例如 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 来表示数据结构使代码更易于理解和维护。事实上,您可以轻松地在 Point
或 Comparator<Point>
class.
上实现 Comparable
我有一个点列表,其中每个点都是一个很小的列表 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)
观察:
- 输入在
x
上按升序排序。 (5, 12)
正确地放在(5, 10)
之前。(9, -15)
正确地放在了(9, -1000)
. 之前
- 然而,
(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
的所有实例(以及 Byte
、Short
和 Long
) 在 [-128; 127]
范围内。 IE。这些实例被重用,假设 int
的值 12
的自动装箱结果将是 always 相同的对象。
因为您的示例中的小值,如 3
、5
、12
将由 单个对象 表示,所以对它们进行了比较==
没有问题。但是对于两个值为 10001
的 Integer
实例与 ==
比较的结果将是 false
因为在这种情况下将是两个不同的对象在堆中。
缓存常用对象的方法称为Flyweight design pattern。它很少在 Java 中使用,因为当 吨相同的对象 被 创建并且销毁。只有在这种情况下,缓存这些对象才能显着提高性能。据我所知,它用于游戏开发。
利用物体的力量
Point
必须是对象,而不是列表,如
- 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
界面中的 default
和 static
方法创建多个自定义比较器,例如 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 来表示数据结构使代码更易于理解和维护。事实上,您可以轻松地在 Point
或 Comparator<Point>
class.
Comparable