Java8 stream 中利用 groupingBy 進(jìn)行多字段分組求和案例
Java8的groupingBy實(shí)現(xiàn)集合的分組,類似Mysql的group by分組功能,注意得到的是一個(gè)map
對集合按照單個(gè)屬性分組、分組計(jì)數(shù)、排序
List<String> items =
Arrays.asList("apple", "apple", "banana",
"apple", "orange", "banana", "papaya");
// 分組
Map<String, List<String>> result1 = items.stream().collect(
Collectors.groupingBy(
Function.identity()
)
);
//{papaya=[papaya], orange=[orange], banana=[banana, banana], apple=[apple, apple, apple]}
System.out.println(result1);
// 分組計(jì)數(shù)
Map<String, Long> result2 = items.stream().collect(
Collectors.groupingBy(
Function.identity(), Collectors.counting()
)
);
// {papaya=1, orange=1, banana=2, apple=3}
System.out.println(result2);
Map<String, Long> finalMap = new LinkedHashMap<>();
//分組, 計(jì)數(shù)和排序
result2.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
// {apple=3, banana=2, papaya=1, orange=1}
System.out.println(finalMap);
集合按照多個(gè)屬性分組
1.多個(gè)屬性拼接出一個(gè)組合屬性
public static void main(String[] args) {
User user1 = new User("zhangsan", "beijing", 10);
User user2 = new User("zhangsan", "beijing", 20);
User user3 = new User("lisi", "shanghai", 30);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
Map<String, List<User>> collect = list.stream().collect(Collectors.groupingBy(e -> fetchGroupKey(e)));
//{zhangsan#beijing=[User{age=10, name='zhangsan', address='beijing'}, User{age=20, name='zhangsan', address='beijing'}],
// lisi#shanghai=[User{age=30, name='lisi', address='shanghai'}]}
System.out.println(collect);
}
private static String fetchGroupKey(User user){
return user.getName() +"#"+ user.getAddress();
}
2.嵌套調(diào)用groupBy
User user1 = new User("zhangsan", "beijing", 10);
User user2 = new User("zhangsan", "beijing", 20);
User user3 = new User("lisi", "shanghai", 30);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
Map<String, Map<String, List<User>>> collect
= list.stream().collect(
Collectors.groupingBy(
User::getAddress, Collectors.groupingBy(User::getName)
)
);
System.out.println(collect);
3. 使用Arrays.asList
我有一個(gè)與Web訪問記錄相關(guān)的域?qū)ο罅斜?。這些域?qū)ο罂梢詳U(kuò)展到數(shù)千個(gè)。
我沒有資源或需求將它們以原始格式存儲在數(shù)據(jù)庫中,因此我希望預(yù)先計(jì)算聚合并將聚合的數(shù)據(jù)放在數(shù)據(jù)庫中。
我需要聚合在5分鐘窗口中傳輸?shù)目傋止?jié)數(shù),如下面的sql查詢
select round(request_timestamp, '5') as window, --round timestamp to the nearest 5 minute cdn, isp, http_result_code, transaction_time, sum(bytes_transferred) from web_records group by round(request_timestamp, '5'), cdn, isp, http_result_code, transaction_time
在java 8中,我當(dāng)前的第一次嘗試是這樣的,我知道這個(gè)解決方案類似于Group by multiple field names in java 8
Map<Date, Map<String, Map<String, Map<String, Map<String, Integer>>>>>>> aggregatedData =
webRecords
.stream()
.collect(Collectors.groupingBy(WebRecord::getFiveMinuteWindow,
Collectors.groupingBy(WebRecord::getCdn,
Collectors.groupingBy(WebRecord::getIsp,
Collectors.groupingBy(WebRecord::getResultCode,
Collectors.groupingBy(WebRecord::getTxnTime,
Collectors.reducing(0,
WebRecord::getReqBytes(),
Integer::sum)))))));
這是可行的,但它是丑陋的,所有這些嵌套的地圖是一個(gè)噩夢!要將地圖“展平”或“展開”成行,我必須這樣做
for (Date window : aggregatedData.keySet()) {
for (String cdn : aggregatedData.get(window).keySet()) {
for (String isp : aggregatedData.get(window).get(cdn).keySet()) {
for (String resultCode : aggregatedData.get(window).get(cdn).get(isp).keySet()) {
for (String txnTime : aggregatedData.get(window).get(cdn).get(isp).get(resultCode).keySet()) {
Integer bytesTransferred = aggregatedData.get(window).get(cdn).get(distId).get(isp).get(resultCode).get(txnTime);
AggregatedRow row = new AggregatedRow(window, cdn, distId...
如你所見,這是相當(dāng)混亂和難以維持。
有誰知道更好的方法嗎?任何幫助都將不勝感激。
我想知道是否有更好的方法來展開嵌套的映射,或者是否有一個(gè)庫允許您對集合進(jìn)行分組。
最佳答案
您應(yīng)該為地圖創(chuàng)建自定義密鑰。最簡單的方法是使用Arrays.asList:
Function<WebRecord, List<Object>> keyExtractor = wr ->
Arrays.<Object>asList(wr.getFiveMinuteWindow(), wr.getCdn(), wr.getIsp(),
wr.getResultCode(), wr.getTxnTime());
Map<List<Object>, Integer> aggregatedData = webRecords.stream().collect(
Collectors.groupingBy(keyExtractor, Collectors.summingInt(WebRecord::getReqBytes)));
在這種情況下,鍵是按固定順序列出的5個(gè)元素。不是很面向?qū)ο螅芎唵?。或者,您可以定義自己的表示自定義鍵的類型,并創(chuàng)建適當(dāng)?shù)膆ashCode/equals實(shí)現(xiàn)。
補(bǔ)充知識:java8 新特性 Stream流 分組 排序 過濾 多條件去重 (最小、最大、平均、求和)
什么是 Stream?
Stream 是用函數(shù)式編程方式在集合類上進(jìn)行復(fù)雜操作的工具,其集成了Java 8中的眾多新特性之一的聚合操作,開發(fā)者可以更容易地使用Lambda表達(dá)式,并且更方便地實(shí)現(xiàn)對集合的查找、遍歷、過濾以及常見計(jì)算等。話不多說,直接上代碼。
List<User> list = new ArrayList<User>();
list = Arrays.asList(
new User("小強(qiáng)", 11, "男"),
new User("小玲", 15, "女"),
new User("小虎", 23, "男"),
new User("小雨", 26, "女"),
new User("小飛", 19, "男"),
new User("小玲", 15, "女")
);
//分組
Map<String, List<User>> listMap = list.stream().collect(Collectors.groupingBy(User::getSex));
for(String key:listMap.keySet()){
System.out.print(key+"組:");
listMap.get(key).forEach(user -> System.out.print(user.getName()));
System.out.println();
}
//排序
list.stream().sorted(Comparator.comparing(user-> user.getAge()))
.forEach(user -> System.out.println(user.getName()));
//過濾
list.stream().filter(user -> user.getSex().equals("男")).collect(Collectors.toList())
.forEach(user -> System.out.println(user.getName()));
//多條件去重
list.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(user -> user.getAge() + ";" + user.getName()))), ArrayList::new))
.forEach(user -> System.out.println(user.getName()));
//最小值
Integer min = list.stream().mapToInt(User::getAge).min().getAsInt();
//最大值
Integer max = list.stream().mapToInt(User::getAge).max().getAsInt();
//平均值
Double average = list.stream().mapToInt(User::getAge).average().getAsDouble();
//和
Integer sum = list.stream().mapToInt(User::getAge).sum();
System.out.println("最小值:"+min+", 最大值"+max+", 平均值:"+average+", 和:"+sum);
//分組求和
Map<String, IntSummaryStatistics> collect = list.stream().collect(Collectors.groupingBy(User::getSex, Collectors.summarizingInt(User::getAge)));
IntSummaryStatistics statistics1 = collect.get("男");
IntSummaryStatistics statistics2 = collect.get("女");
System.out.println(statistics1.getSum());
System.out.println(statistics1.getAverage());
System.out.println(statistics1.getMax());
System.out.println(statistics1.getMin());
System.out.println(statistics1.getCount());
System.out.println(statistics2.getSum());
System.out.println(statistics2.getAverage());
System.out.println(statistics2.getMax());
System.out.println(statistics2.getMin());
System.out.println(statistics2.getCount());
//提取list中兩個(gè)屬性值,轉(zhuǎn)為map
Map<String, String> userMap = list.stream().collect(Collectors.toMap(User::getName, User::getSex));
System.out.println(JsonUtil.toJson(userMap))
//取出所有名字
List<String> names = list.stream().map(User::getName).collect(Collectors.toList());
System.out.println(JsonUtil.toJson(names))
以上這篇Java8 stream 中利用 groupingBy 進(jìn)行多字段分組求和案例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- JAVA JDK8 List分組的實(shí)現(xiàn)和用法
- JAVA JDK8 List分組獲取第一個(gè)元素的方法
- 使用Java8進(jìn)行分組(多個(gè)字段的組合分組)
- java8快速實(shí)現(xiàn)List轉(zhuǎn)map 、分組、過濾等操作
- Java8使用Stream流實(shí)現(xiàn)List列表查詢、統(tǒng)計(jì)、排序以及分組
- java8 stream自定義分組求和并排序的實(shí)現(xiàn)
- java8 如何實(shí)現(xiàn)分組計(jì)算數(shù)量和計(jì)算總數(shù)
- JAVA簡單分組的算法實(shí)現(xiàn)
- Java按周對事件進(jìn)行分組的實(shí)現(xiàn)示例
相關(guān)文章
spring security的BCryptPasswordEncoder加密和對密碼驗(yàn)證的原理分析
文章介紹了加密算法和hash算法的基本概念,以及BCryptPasswordEncoder加密和解密的原理,加密算法是可逆的,需要加鹽以保證安全性,BCryptPasswordEncoder通過生成鹽值并在加密和解密過程中使用,確保相同的明文每次加密結(jié)果不同,從而提高安全性2024-11-11
關(guān)于Java如何用好線程池的方法分享(建議收藏)
這篇文章主要來和大家分享幾個(gè)關(guān)于Java如何用好線程池的建議,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2023-06-06
java 用遞歸獲取一個(gè)目錄下的所有文件路徑的小例子
還是日志的問題,log4j生成的日志文件,自動(dòng)保存到月份所在的文件夾中,需要獲取到所有的日志文件,包括文件夾2013-09-09
intellij idea使用git stash暫存一次提交的操作
這篇文章主要介紹了intellij idea使用git stash暫存一次提交的操作,具有很好的參考價(jià)值希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Java解析調(diào)用webservice服務(wù)的返回XML串詳解
這篇文章主要介紹了Java解析調(diào)用webservice服務(wù)的返回XML串詳解的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
MyBatis-Plus集成Druid環(huán)境搭建的詳細(xì)教程
這篇文章主要介紹了MyBatis-Plus集成Druid環(huán)境搭建的詳細(xì)教程,需要的朋友可以參考下2020-08-08

