6 回答

TA貢獻(xiàn)1906條經(jīng)驗(yàn) 獲得超3個(gè)贊
嘗試使用groupingBy,summingLong如下comparingLong所示
Map<Month, BuyerDetails> topBuyers = orders.stream()
.collect(Collectors.groupingBy(Order::getOrderMonth,
Collectors.groupingBy(Order::getCustomer,
Collectors.summingLong(Order::getAmount))))
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
order -> order.getValue().entrySet().stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.map(cust -> new BuyerDetails(cust.getKey(), cust.getValue())).get()));
輸出
{
"MARCH": { "customer": "Dan", "amount": 300 },
"APRIL": { "customer": "Jenny", "amount": 550 }
}

TA貢獻(xiàn)1775條經(jīng)驗(yàn) 獲得超11個(gè)贊
有沒有辦法在一個(gè)流中解決上述任務(wù)?
這取決于你所說的“在一個(gè)流中”是什么意思。您想要執(zhí)行一個(gè)縮減操作,該操作的最佳特征可能是一系列縮減的組合:
按月對(duì)訂單進(jìn)行分組
在每個(gè)月組內(nèi),匯總每個(gè)客戶的訂單以產(chǎn)生總金額
在每個(gè)月的每個(gè)客戶聚合結(jié)果組中,選擇數(shù)量最大的一個(gè)(注意:在關(guān)系的情況下沒有明確定義)
從 Stream API 的角度來看,對(duì)流執(zhí)行這些單獨(dú)的歸約中的任何一個(gè)都是對(duì)該流的終端操作。您可以使用新流處理結(jié)果,甚至在語法上將其鏈接在一起,但盡管這可能采用單個(gè)方法調(diào)用鏈的語法形式,但它不會(huì)構(gòu)成在單個(gè)流上發(fā)生的所有操作。
您還可以創(chuàng)建一個(gè)Collector
(或一個(gè)的組件),以便通過收集輸入元素流直接獲得結(jié)果,但在內(nèi)部,該收集器仍需要通過內(nèi)部創(chuàng)建和消耗額外的來執(zhí)行單獨(dú)的歸約流,或通過非流 API 執(zhí)行相同的任務(wù)。如果您再次計(jì)算這些內(nèi)部操作,不,它不構(gòu)成對(duì)單個(gè)流的執(zhí)行操作。(但是,如果您不考慮這些內(nèi)部縮減,那么是的,這一切都在一個(gè)流中完成。)

TA貢獻(xiàn)1757條經(jīng)驗(yàn) 獲得超7個(gè)贊
好吧,我們開始吧!以下代碼將為您提供所需的內(nèi)容,只需調(diào)用 1 次即可stream():
Map<Month, BuyerDetails> grouped = orders.stream().collect(
Collectors.groupingBy(Order::getOrderMonth,
Collectors.collectingAndThen(
Collectors.groupingBy(Order::getCustomer,
Collectors.summingLong(Order::getAmount)
),
((Function<Map<String,Long>, Map.Entry<String,Long>>)
map -> Collections.max(
map.entrySet(), Comparator.comparingLong(Map.Entry::getValue)
)
).andThen(
e -> new BuyerDetails(e.getKey(),e.getValue())
)
)
)
);
System.out.println(grouped);
輸出:
{MARCH={ customer='Dan', amount=300 }, APRIL={ customer='Jenny', amount=550 }}
現(xiàn)在,這有點(diǎn)奇怪,所以讓我們逐行檢查它,看看發(fā)生了什么:
Map<Month, BuyerDetails> grouped = orders.stream().collect(
首先,我們流式傳輸我們的訂單,
Collectors.groupingBy(Order::getOrderMonth,
按月分組,我們發(fā)現(xiàn):
Collectors.collectingAndThen(
Collectors.groupingBy(Order::getCustomer,
每個(gè)客戶和
Collectors.summingLong(Order::getAmount)
),
他們一個(gè)月內(nèi)的總訂單。
((Function<Map<String,Long>, Map.Entry<String,Long>>)
(我們轉(zhuǎn)換為Function,所以我們可以使用andThen我們定義的 lambda 函數(shù)之類的方法)
map -> Collections.max(
map.entrySet(), Comparator.comparingLong(Map.Entry::getValue)
)
對(duì)于每個(gè)月,我們都會(huì)找到具有最大訂單金額的客戶。
).andThen(
然后我們
e -> new BuyerDetails(e.getKey(),e.getValue())
為所述客戶創(chuàng)建新的買家詳細(xì)信息
)
)
)
);
并收集所有 Month/BuyerDetail 對(duì)。
System.out.println(grouped);
最后,我們打印創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)。

TA貢獻(xiàn)1783條經(jīng)驗(yàn) 獲得超4個(gè)贊
它有一個(gè)嵌套流,所以它不是一個(gè)流,它返回Map<String, Optional<BuyerDetails>>。
orders.stream()
.collect(
Collectors.groupingBy(Order::getOrderMonth,
Collectors.collectingAndThen(
Collectors.groupingBy(
Order::getCustomer,
Collectors.summarizingLong(Order::getAmount)
),
e -> e.entrySet()
.stream()
.map(entry -> new BuyerDetails(entry.getKey(), entry.getValue().getSum()))
.max(Comparator.comparingLong(BuyerDetails::getAmount))
)
)
)
所以有3個(gè)步驟:
按月分組Collectors.groupingBy(Order::getOrderMonth,
按客戶名稱分組并匯總總訂單金額Collectors.groupingBy(Order::getCustomer, Collectors.summarizingLong( Order::getAmount))
過濾中間結(jié)果,只留下最大金額的客戶max(Comparator.comparingLong(BuyerDetails::getAmount))
輸出是
{
APRIL = Optional [ BuyerDetails { customer = 'Jenny', amount = 550 } ],
MARCH = Optional [ BuyerDetails { customer = 'Dan', amount = 300 } ]
}
我也很好奇這是否可以在沒有額外流的情況下完成。

TA貢獻(xiàn)1775條經(jīng)驗(yàn) 獲得超8個(gè)贊
我的方法(3 個(gè)流):
private static void solution1(List<Order> orders) {
final Map<Month, BuyerDetails> topBuyers = orders.stream().collect(
Collectors.groupingBy(order -> order.getCustomer() + "$" + order.getOrderDate().getYear() + "." +
order.getOrderMonth(),
Collectors.reducing((ord1, ord2) -> {
ord1.setAmount(ord1.getAmount() + ord2.getAmount());
return ord1;
}))).values().stream()
.collect(Collectors.groupingBy(order -> order.get().getOrderMonth(),
maxBy(Comparator.comparing(order -> order.get().getAmount())))).values().stream()
.collect(
toMap((key) -> key.get().get().getOrderMonth(),
key -> new BuyerDetails(key.get().get().getCustomer(), key.get().get().getAmount())
)
);
}

TA貢獻(xiàn)2039條經(jīng)驗(yàn) 獲得超8個(gè)贊
這不能用單個(gè)流來完成,因?yàn)?和sum都是max終端操作,它們不能應(yīng)用于同一個(gè)流。最好把它分成兩個(gè)操作
Map<Month, Map<String, Long>> sumsByMonth = orders.stream().collect(
Collectors.groupingBy(
Order::getOrderMonth,
Collectors.groupingBy(
Order::getCustomer,
Collectors.mapping(
Order::getAmount,
Collectors.reducing(0L, a -> a, (a1, a2) -> a1 + a2)
)
)
)
);
Map<Month, BuyerDetails> topBuyers = sumsByMonth.entrySet().stream().collect(
Collectors.toMap(
Map.Entry::getKey,
sums -> sums.getValue().entrySet().stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.map(e -> new BuyerDetails(e.getKey(), e.getValue()))
.get()
)
);
添加回答
舉報(bào)