我有一個點串列,其中每個點都是一個很小的 ??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);
});
這是排序前的輸入:
(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。
Feel like I am missing something trivial. I experimented with a few other ways of writing the comparator like using Integer.compare(a, b) or just a.compareTo(t), but got the same result.
Finally, I changed the representation of point from List<Integer> to int[] and wrote the same comparator again. See results below:
Collections.sort(points, (a, b) -> {
if (a[0] != b[0])
return a[0] - b[0];
return b[1] - a[1];
});
Input before sorting:
(2, 1000)
(9, -1000)
(3, 15)
(9, -150
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)
After sorting:
(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -8)
(10001, -10)
So list of arrays is getting sorted correctly as (10001, -8) was correctly put before (10001, -10).
I am not able to understand why changing the representation of point resolved the issue and hence this question. I can give more details on how I am creating the List of points if required.
uj5u.com熱心網友回復:
我錯過了一些微不足道的東西
方法equals()應該用于物件比較。雙等號==檢查兩個參考是否指向記憶體中的同一個物件。
如果您將比較器內部的條件更改為!a.get(0).equals(b.get(0))它將正常作業。
但是,(10001, -10)放在(10001, -8)之前。即使-8大于-10。
出現這種行為的原因是JVMInteger快取了 range 中的(以及Byte, Shortand Long) 的所有實體[-128; 127]。即這些實體被重用,假設自動裝箱的結果int將12始終是同一個物件。
因為您的示例中的小值(如3, 5, )12將由單個 object表示,因此將它們與==沒有問題的比較。但是==對于兩個Integer值為 的實體進行比較的結果10001將是,因為在這種情況下,堆中false將有兩個不同的物件。
快取常用物件的方法稱為享元設計模式。它在Java中很少使用,因為這種模式可以在創建和銷毀大量相同物件時帶來好處。只有在這種情況下,快取這些物件才能顯著提高性能。據我所知,它用于游戲開發。
使用物體的力量
Point正如Code-Apprentice在他的回答中指出的那樣,必須是一個物件,而不是一個串列。使用物件的力量,不要過度使用集合。它帶來了幾個優點:
- 類為您提供了一個結構,當您從物件的角度思考時,更容易組織您的代碼;
- 在類中宣告的行為是可重用的并且更容易測驗;
- 有了類,你可以使用多型的力量。
注意:物件也可能被濫用,其中一個可能的指標是當一個類沒有宣告除 getter 之外的任何行為,并且它的資料在這個類之外的代碼中以某種方式被處理。
盡管點(作為幾何物件)的概念并不復雜,但在方法方面有一些有用的選項。例如,您可以使Point類的實體能夠檢查它們是否水平或垂直對齊,或者兩個點是否在特定的半徑內。并且Point類可以實作Comparable介面,這樣點就可以在沒有Comparator.
排序
隨著Java 8方法sort()
被添加到List介面。它需要一個 的實體Comparator,并且如果串列的元素實作了可比較,并且您希望它們按照自然順序進行排序,null則可以作為引數傳遞。
如果指定的比較器為空,則此串列中的所有元素都必須實作 Comparable 介面,并且應使用元素的自然順序。
Collections因此,您可以直接在點串列上呼叫方法,而不是使用實用程式類sort()(假設Point實作Comparable<Point>):
points.sort(null); // the same as points.sort(Comparator.naturalOrder());
此外,您可以通過使用介面中的方法來創建多個自定義比較器,例如defaultcompareInt static( )和thenComparing ()。Comparator
(有關如何使用Java 8方法構建比較器的更多資訊,請查看本教程)
uj5u.com熱心網友回復:
@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];
});
除此之外,我建議創建一個Point類:
class Point {
public int x;
public int y;
}
在這里,我使用public欄位來遵循結構模式。如果您想添加 getter 和 setter 以及其他行為,請隨意這樣做。使用類來表示資料的結構使代碼更易于理解和維護。事實上,您可以輕松地Comparable在一個Point或一個Comparator<Point>類上實作。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/439275.html
標籤:java list sorting comparator
