当前位置: 首页 > news >正文

Java stream groupingBy sorted 实现多条件排序与分组的最佳实践

1. 数据初始化

这一部分代码用于创建 Product 对象并将它们添加到 result 列表中。

// 初始化数据
List<Product> result = new ArrayList<>();
List<Product> resp = new ArrayList<>();// 添加产品数据
result.add(new Product("手机A", 1500, "电子", 3, 5));
result.add(new Product("手机B", 1600, "电子", 3, 5));
result.add(new Product("手机C", 1800, "电子", 3, 5));
result.add(new Product("电脑A", 13000, "电子", 3, 6));
result.add(new Product("电脑B", 15000, "电子", 3, 6));
result.add(new Product("电脑C", 18000, "电子", 3, 6));result.add(new Product("床C", 7000, "家具", 1, 4));
result.add(new Product("椅子A", 500, "家具", 1, 3));
result.add(new Product("椅子B", 400, "家具", 1, 3));
result.add(new Product("椅子C", 300, "家具", 1, 3));result.add(new Product("牙膏A", 15, "洗护", 2, 1));
result.add(new Product("牙膏B", 25, "洗护", 2, 1));
result.add(new Product("牙膏C", 18, "洗护", 2, 1));
result.add(new Product("洗面奶A", 60, "洗护", 2, 2));
result.add(new Product("洗面奶B", 70, "洗护", 2, 2));
result.add(new Product("洗面奶C", 80, "洗护", 2, 2));
说明
  • Product:表示一个产品对象,包含以下属性:
    • name:产品名称。
    • price:产品价格。
    • type:产品类型(如电子、家具、洗护)。
    • seq0seq1:排序辅助字段。
  • result 列表:存储所有产品对象。
  • resp 列表:用于存储最终输出的结果。

2. 按价格排序并分组

这一部分代码对 result 列表中的产品按价格排序后,按 type 字段分组。

// 按价格排序并分组
Map<String, List<Product>> collect = result.stream().sorted(Comparator.comparing(Product::getPrice)) // 按价格升序排序.collect(Collectors.groupingBy(Product::getType, // 按类型分组LinkedHashMap::new, // 保持分组顺序Collectors.toList() // 分组后每组存为 List));
说明
  • 排序:使用 Comparator.comparing(Product::getPrice) 对产品按价格升序排序。
  • 分组:使用 Collectors.groupingBytype 字段分组。
  • 结果collect 是一个 Map,键为产品类型(如 “电子”、“家具”),值为对应类型的产品列表。

3. 对分组后的数据排序

这一部分代码对每个分组内的产品列表进行排序,先按 seq1 正序,再按价格倒序。

// 对分组后的数据按 seq1 正序和价格倒序排序
Map<String, List<Product>> sortedCollect = result.stream().collect(Collectors.groupingBy(Product::getType, // 按类型分组LinkedHashMap::new, // 保持分组顺序Collectors.collectingAndThen(Collectors.toList(), // 先收集到 Listlist -> list.stream().sorted(Comparator.comparing(Product::getPrice).reversed()) // 价格倒序.sorted(Comparator.comparing(Product::getSeq1)) // seq1 正序.collect(Collectors.toList()) // 排序后收集为 List)));
说明
  • 分组:与上一步类似,按 type 字段分组。
  • 排序逻辑
    1. 价格倒序Comparator.comparing(Product::getPrice).reversed()
    2. seq1 正序Comparator.comparing(Product::getSeq1)
    3. 排序优先级:先按 seq1 排序,再按价格排序。
  • 结果sortedCollect 是一个 Map,每个分组内的产品列表已按上述规则排序。

4. 对分组的键排序

这一部分代码对分组的键(即产品类型)按字典序排序。

// 对分组后的 key 进行排序
Map<String, List<Product>> sortedMap2 = sortedCollect.entrySet().stream().sorted(Map.Entry.comparingByKey()) // 按键(类型)排序.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue,(oldVal, newVal) -> oldVal,LinkedHashMap::new // 保持插入顺序));
说明
  • 排序逻辑Map.Entry.comparingByKey() 按键(类型)字典序排序。
  • 结果sortedMap2 是一个按类型排序的 Map,每个分组内的产品列表已按规则排序。

5. 按顺序取出每组的第 i 个元素

这一部分代码从每个分组中依次取出第 i 个元素,直到所有元素都被取出。

// 遍历分组数据,按顺序取出每组的第 i 个元素
int index = 0;
boolean done = false;while (!done) {done = true;for (String key : sortedMap2.keySet()) {List<Product> group = sortedMap2.get(key);if (index < group.size()) {String name = sortedMap2.get(key).get(index).name;System.out.println("name: " + name);resp.add(group.get(index)); // 添加到结果列表done = false; // 如果还有未取出的元素,继续循环}}index++;
}
说明
  • 逻辑
    1. 遍历每个分组,取出第 index 个元素。
    2. 如果某个分组的元素已取完,则跳过。
    3. 当所有分组的元素都取完时,退出循环。
  • 结果resp 列表按顺序存储所有产品。

6. 按每组的第 i 个元素重新排序

这一部分代码实现了另一种遍历方式,按每组的第 i 个元素重新排序。

// 计算每组的最大长度
int count = 0;
for (String key : sortedMap2.keySet()) {count = Math.max(count, sortedMap2.get(key).size());
}// 按每组的第 i 个元素重新排序
int j = 0;
for (int i = 0; i < count; i++) {for (String key : sortedMap2.keySet()) {if (i >= sortedMap2.get(key).size()) {continue; // 跳过超出范围的元素}String name = sortedMap2.get(key).get(i).name;System.out.println("name: " + name);resp.add(j, sortedMap2.get(key).get(i)); // 插入到结果列表j++;}
}
说明
  • 逻辑
    1. 计算每组的最大长度 count
    2. 遍历每组的第 i 个元素,按顺序插入到 resp 列表中。
  • 结果resp 列表存储按每组第 i 个元素排序的结果。

7. 产品类定义

Product 类是代码的核心数据结构,定义如下:

static class Product {String name;int price;String type;int seq0;int seq1;public Product(String name, int price, String type, int seq0, int seq1) {this.name = name;this.price = price;this.type = type;this.seq0 = seq0;this.seq1 = seq1;}public String getName() {return name;}public int getPrice() {return price;}public String getType() {return type;}public int getSeq0() {return seq0;}public int getSeq1() {return seq1;}
}

总结

通过拆分代码,我们可以清晰地看到每个部分的功能:

  1. 数据初始化。
  2. 按价格排序并分组。
  3. 对分组内的产品排序。
  4. 对分组的键排序。
  5. 按顺序取出每组的第 i 个元素。
  6. 按每组的第 i 个元素重新排序。

如果需要进一步优化或补充说明,请随时告知!

http://www.lryc.cn/news/505325.html

相关文章:

  • JAVA:代理模式(Proxy Pattern)的技术指南
  • 爬取Q房二手房房源信息
  • Ansible自动化运维(五) 运维实战
  • K-means算法的python实现
  • 客户端(浏览器)vue3本地预览txt,doc,docx,pptx,pdf,xlsx,csv,
  • [SZ901]JTAG高速下载设置(53Mhz)
  • docker springboot 运维部署详细实例
  • Linux 查看目录命令 ls 详细介绍
  • React Native状态管理器Redux、MobX、Context API、useState
  • Three.js资源-模型下载网站
  • linux 添加默认网关
  • 【学习笔记】深入浅出详解Pytorch中的View, reshape, unfold,flatten等方法。
  • CTFHUB-web(SSRF)
  • 分解质因数
  • 前景物体提取
  • Kotlin复习
  • 【AI日记】24.12.17 kaggle 比赛 2-6 | 把做饭看成一种游戏 | 咖喱牛肉
  • 操作系统(14)请求分页
  • uniapp navigateTo、redirectTo、reLaunch等页面路由跳转方法的区别
  • 模型 A/B测试(科学验证)
  • 谷歌发布升级版AI视频生成器Veo 2与图像生成器Imagen 3
  • 快速掌握源码部署Filebeat
  • C++ 哈希表封装unordered_map 和 unordered_set
  • pymysql 入门
  • Leecode刷题C++之形成目标字符串需要的最少字符串数①
  • Linux应用开发————mysql数据库
  • 4_使用 HTML5 Canvas API (3) --[HTML5 API 学习之旅]
  • docker build次数过多,导致磁盘内存不足:ERROR: no space left on device
  • LDO和DC-DC的区别、DCDC和LDO主要指标
  • LeetCode hot100-81