在 Java 中根據另一個清單對一個清單進行排序
1. 概述
根據另一個清單的順序對清單進行排序是 Java 中的常見任務,並且存在多種方法來實現此目的。
在本教程中,我們將看到在 Java 中根據另一個清單對清單進行排序的不同方法。
2. 範例
讓我們考慮一個場景,其中我們有一個產品清單( productList
和另一個清單( shoppingCart,
它代表使用者的購物車。 shoppingCart
包含各種產品ID,我們需要依照產品在購物車中出現的順序顯示產品:
List<String> productList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");<br />List<String> shoppingCart = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
在上面的範例中, productList
是實際有訂單的列表, shoppingCart
是需要根據productList.
排序後,順序應該是:
Pizza
Burger
Fries
Coke
3. 使用for
循環迭代List
我們可以使用標準的 for 迴圈根據另一個清單對清單進行排序。在這種方法中,我們建立一個新列表,它將按排序順序傳回元素。此循環迭代listWithOrder
列表,並依指定順序將listToSort
中的元素加入sortedList
中。結果是根據listWithOrder
列表中元素的順序sortedList
的List:
List<String> sortUsingForLoop(List<String> listToSort, List<String> listWithOrder) {
List<String> sortedList = new ArrayList<>();
for (String element: listWithOrder) {
if (listToSort.contains(element)) {
sortedList.add(element);
}
}
return sortedList;
}
讓我們測試一下這種方法來對上面的範例進行排序:
public void givenTwoList_whenUsingForLoop_thenSort() {
List<String> listWithOrder = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
List<String> listToSort = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
sortUsingForLoop(listToSort, listWithOrder);
List<String> expectedSortedList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
assertEquals(expectedSortedList, listWithOrder);
}
4. 使用Comparator
接口
在這種方法中,我們利用 Java 的Comparator
介面的靈活性來建立自訂比較器。比較器將基於參考清單或具有實際順序的清單中的元素索引。讓我們來看看它如何讓我們對列表進行排序:
void sortUsingComparator(List<String> listToSort, List<String> listWithOrder) {
listToSort.sort(Comparator.comparingInt(listWithOrder::indexOf));
}
Comparator.comparingInt(listWithOrder::indexOf)
構造允許我們按照 listWithOrder 中元素的出現順序對listToSort
列表進行排序listWithOrder.
讓我們使用這種方法對上面討論的範例進行排序:
public void givenTwoList_whenUsingComparator_thenSort() {
List<String> listWithOrder = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
List<String> listToSort = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
sortUsingComparator(listToSort, listWithOrder);
List<String> expectedSortedList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
assertEquals(expectedSortedList, listToSort);
}
它是一個簡潔且可讀的解決方案,避免了對額外資料結構的需要,並提供了一種清晰、直接的方式。但是,需要注意的是,大型清單的效能可能會下降,因為indexOf()
操作具有線性時間複雜度。
5. 使用串流API
我們還可以使用基於 Stream API 的方法根據另一個清單對清單進行排序。首先,我們將透過Collectors.toMap()
收集器在listWithOrder
中建立元素及其索引之間的對應.
之後,產生的映射將用於透過Comparator.comparingInt()
方法對listToSort
進行排序:
void sortUsingStreamAPI(List<String> listToSort, List<String> listWithOrder) {
Map<String,Integer> indicesMap = listWithOrder.stream().collect(Collectors.toMap(e -> e, listWithOrder::indexOf));
listToSort.sort(Comparator.comparingInt(indicesMap::get));
}
讓我們測試一下這種方法來對上面的範例進行排序:
public void givenTwoList_whenUsingStreamAPI_thenSort() {
List<String> listWithOrder = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
List<String> listToSort = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
sortUsingCustomComparator(listToSort, listWithOrder);
List<String> expectedSortedList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
assertEquals(expectedSortedList, listToSort);
}
Stream API 方法提供了一個乾淨且現代化的解決方案。然而,重要的是要注意大型列表的潛在開銷,因為建立映射涉及迭代整個列表。
6. 使用Map
在這個方法中,我們利用 Java Map
的強大功能在引用清單listWithOrder
中的元素與其對應索引之間建立直接映射。映射中的鍵值對由listWithOrder
中的元素作為鍵及其索引作為值組成:
void sortUsingMap(List<String> listToSort, List<String> listWithOrder) {
Map<String, Integer> orderedIndicesMap = new HashMap<>();
for (int i = 0; i < listWithOrder.size(); i++) {
orderedIndicesMap.put(listWithOrder.get(i), i);
}
listToSort.sort(Comparator.comparingInt(orderedIndicesMap::get));
}
讓我們測試一下這種方法來對上面的範例進行排序:
public void givenTwoList_whenUsingMap_thenSort() {
List<String> listWithOrder = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
List<String> listToSort = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
sortUsingMap(listToSort, listWithOrder);
List<String> expectedSortedList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
assertEquals(expectedSortedList, listToSort);
}
使用Map
為我們提供了優於indexOf()
方法的優勢,特別是在涉及大型清單、重複尋找或效能敏感應用程式的場景中。
7.使用Guava的Ordering.explicit()
Guava 是一個廣泛使用的 Java 函式庫,它提供了一種根據另一個清單的元素順序對清單進行排序的便捷方法。讓我們先在pom.xml
檔中加入此依賴項:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.0.0-jre</version>
</dependency>
Guava 的explicit()
方法允許我們根據特定的順序建立一個比較器。 Ordering
類別是不可變的,因此結果將是一個新的排序列表,而原始列表(即listToSort,
將保持不變。
List<String> sortUsingGuava(List<String> listToSort, List<String> listWithOrder) {
Ordering<String> explicitOrdering = Ordering.explicit(listWithOrder);
List<String> sortedList = explicitOrdering.sortedCopy(listToSort);
return sortedList;
}
在上面的範例中, sortedCopy()
方法負責建立排序清單。讓我們測試一下這個方法:
public void givenTwoList_whenUsingGuavaExplicit_thenSort() {
List<String> listWithOrder = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
List<String> listToSort = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
sortUsingGuava(listToSort, listWithOrder);
List<String> expectedSortedList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
assertEquals(expectedSortedList, listWithOrder);
}
8.使用Vavr
Vavr 是Java 8+ 的函數庫,提供不可變資料型別和函數控制結構。為了使用 Vavr,我們首先需要新增此依賴項:
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.10.4</version>
</dependency>
Vavr 提供了sortBy()
方法,可用於根據另一個清單(即listToSort,
中指定的順序對清單(即listToOrder
進行排序。結果將儲存在新列表sortedList,
而原始listToSort
列表將保持不變。讓我們看一個使用 Vavr 的範例:
List<String> sortUsingVavr(List<String> listToSort, List<String> listWithOrder) {
io.vavr.collection.List<String> listWithOrderedElements = io.vavr.collection.List.ofAll(listWithOrder);
io.vavr.collection.List<String> listToSortElements = io.vavr.collection.List.ofAll(listToSort);
io.vavr.collection.List<String> sortedList = listToSortElements.sortBy(listWithOrderedElements::indexOf);
return sortedList.asJava();
}
讓我們測試一下這個方法:
public void givenTwoList_whenUsingVavr_thenSort() {
List<String> listWithOrder = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
List<String> listToSort = Arrays.asList("Pizza", "Burger", "Fries", "Coke");
sortUsingVavr(listToSort, listWithOrder);
List<String> expectedSortedList = Arrays.asList("Burger", "Coke", "Fries", "Pizza");
assertEquals(expectedSortedList, listWithOrder);
}
9. 結論
在本教程中,我們探索了根據另一個清單中元素的順序對清單進行排序的各種方法。選擇適當的方法取決於基於解決方案的簡單性和效能的特定用例。
與往常一樣,原始碼可以在 GitHub 上取得。