使用 Stream API 以群組尋找最小值和最大值的指南
一、簡介
在本教程中,我們將了解如何按值對元素進行分組並找到每組中的最小值和最大值。
我們需要 Java 8 流的基本知識才能更好地理解本教程。另外,有關更多詳細信息,請檢查分組收集器。
2. 了解用例
假設我們有一個包含類別和價格欄位的訂單商品列表,我們希望按類別將商品分組,並在每個類別中找到更便宜和更昂貴的商品。
讓我們來看看訂單商品類別:
public enum OrderItemCategory {
BOOKS, CLOTHING, ELECTRONICS, FURNITURE, OTHER;
}
現在,讓我們定義訂單項目:
public class OrderItem {
private Long id;
private Double price;
private OrderItemCategory category;
// other fields
// getters and setters
}
3. 使用 Streams API 將訂單項目分組
現在,讓我們看看如何按類別將訂購的商品分組,並找出每組中具有最低和最高價格的商品。
分組邏輯的實作:
Map<OrderItemCategory, Pair<Double, Double>> groupByCategoryWithMinMax(List<OrderItem> orderItems) {
Map<OrderItemCategory, DoubleSummaryStatistics> categoryStatistics = orderItems.stream()
.collect(Collectors.groupingBy(OrderItem::getCategory, Collectors.summarizingDouble(OrderItem::getPrice)));
return categoryStatistics.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> Pair.of(entry.getValue().getMin(), entry.getValue().getMax())));
}
OrderProcessor類別包含一個方法groupByCategoryWithMinMax() ,用於處理OrderItem物件的清單。此方法按類別將商品分組,並計算每個類別的最低和最高價格。
首先,它使用 Java 流來收集類別統計資料。它使用Collectors.groupingBy按類別對項目進行分組,並使用Collectors.summarizingDouble匯總價格。
它會建立一個映射,其中鍵是OrderItemCategory ,值是DoubleSummaryStatistics對象,其中包含價格的計數、總和、平均值、最小值和最大值。
接下來,該方法將此映射轉換為另一個映射,其中鍵仍為OrderItemCategory ,但值為Pair<Double, Double> 。該對包含從每個類別的DoubleSummaryStatistics中提取的最低和最高價格。
3.1.了解DoubleSummaryStatistics
DoubleSummaryStatistics提供了一種從double值流收集和匯總統計資料的方法。使用流時,尤其是對於分組或匯總等任務,一次捕獲計數、總和、平均值、最小值和最大值等聚合資料是有益的。
將Collectors.summarizingDouble與流數據結合使用,可以有效收集統計信息,例如每個類別的最低和最高價格,而無需手動計算。 DoubleSummaryStatistics一次聚合多個統計信息,優化效能,尤其是對於大型資料集。
在範例中,我們使用groupByCategoryWithMinMax()方法來計算每個類別的最低和最高價格。然後我們將結果儲存在地圖上。最後,我們將地圖轉換為另一張地圖,將每個類別與一Pair最低和最高價格相關聯。
3.2.瞭解summarizingDouble Collector
summarizingDouble收集器收集一組double值的統計資料。它一次收集計數、總和、平均值、最小值和最大值等數據。此收集器是Collectors實用程式類別的一部分,並傳回DoubleSummaryStatistics物件。
使用summarizingDouble非常有效,因為它避免了對資料的多次傳遞。這使得它非常適合大型數據集。它透過將所有必要的計算封裝在DoubleSummaryStatistics物件中,簡化了取得綜合統計資料的過程。
4. 測試按邏輯分組
讓我們透過測試來檢查我們的分組邏輯:
@Test
void whenOrderItemsAreGrouped_thenGetsMinMaxPerGroup() {
List<OrderItem> items =
Arrays.asList(
new OrderItem(1L, OrderItemCategory.ELECTRONICS, 1299.99),
new OrderItem(2L, OrderItemCategory.ELECTRONICS, 1199.99),
new OrderItem(3L, OrderItemCategory.ELECTRONICS, 2199.99),
new OrderItem(4L, OrderItemCategory.FURNITURE, 220.00),
new OrderItem(4L, OrderItemCategory.FURNITURE, 200.20),
new OrderItem(5L, OrderItemCategory.FURNITURE, 215.00),
new OrderItem(6L, OrderItemCategory.CLOTHING, 50.75),
new OrderItem(7L, OrderItemCategory.CLOTHING, 75.00),
new OrderItem(8L, OrderItemCategory.CLOTHING, 75.00));
OrderProcessor orderProcessor = new OrderProcessor();
Map<OrderItemCategory, Pair<Double, Double>> orderItemCategoryPairMap =
orderProcessor.groupByCategoryWithMinMax(items);
assertEquals(orderItemCategoryPairMap.get(OrderItemCategory.ELECTRONICS), Pair.of(1199.99, 2199.99));
assertEquals(orderItemCategoryPairMap.get(OrderItemCategory.FURNITURE), Pair.of(200.20, 220.00));
assertEquals(orderItemCategoryPairMap.get(OrderItemCategory.CLOTHING), Pair.of(50.75, 75.00));
}
OrderProcessorUnitTest類別測試groupByCategoryWithMinMax()方法。它建立一個OrderItem物件列表,每個物件都有一個類別和價格。然後,它呼叫groupByCategoryWithMinMax()方法按類別對這些商品進行分組,並確定每組的最低和最高價格。然後,測試使用斷言驗證結果是否與每個類別的預期最低和最高價格相符。
5. 結論
在本文中,我們學習了將流項目分組並尋找每組中的最小值和最大值。
與往常一樣,範例的原始程式碼可在 GitHub 上取得。