如何基于两层嵌套属性对List去重并优化Java处理逻辑?
问题:优化嵌套属性的列表处理逻辑
我不确定该如何称呼这种位于两层嵌套结构中的属性。
假设我们有一个List<FruitColor>,其中Fruit和Color是两个实体(均为示例实体)。一种fruit可以对应多种color,一种color也可以对应多种fruit。
实体代码如下:
public class FruitColor { private String fruitColorId; private Fruit fruit; private Color color; private int ripe; //1到3,1代表未成熟,2代表正常成熟,3代表完全成熟 // 更多属性、getter等方法 } public class Fruit { private String fruitId; private String fruitName; // getter等方法 } public class Color { private String colorId; private String colorName; // getter等方法 }
我设想的处理步骤如下:
- 基于
fruitName筛选所有重复条目 - 从两个“重复项”中选择保留一个。这里的“重复项”指仅
fruitName相同但color不同的条目。选择规则由季节/时间过渡指标systemTransition(取值范围为0到100的double类型属性)决定。 - 移除另一个“重复项”。
- 若存在重复项,将果实成熟度降低0.5。
- 设置
factorialRipeness,其值为ripe * systemTransition或ripe * (100 - systemTransition),具体取决于季节进度,以50为分界点。 - 返回包含对应
Color的目标FruitColors列表,并按FactorialRipeness排序。
我知道用大量for循环可以实现,但想了解是否有更高效的实现方式。我曾找到一篇关于按属性过滤的资料,但该方案不支持基于嵌套属性(如fruitName)的过滤。
我已编写了可运行的代码示例(使用了不同实体),但想知道是否有可优化的部分。这里的“更高效”指代码更简洁或执行速度更快。后续我会将方法拆分为更小的模块,因无法使用真实实体,部分逻辑可能存在不合理之处,敬请谅解。
现有代码逻辑:
//方法内逻辑 { List<FruitColor> fruitColors = getAllFCs(); //移除不属于指定两种颜色的FruitColor fruitColors.removeIf(fc -> fc.getColor().getColorId() != presentColor.getColor().getColorId() && fc.getColor().getColorId() != futureColor.getColor().getColorId()); List<FruitColor> suggestedFruits = new ArrayList<>(); //systemTransition代表季节/时间进度(0到100),100表示果实应完全成熟并对应目标颜色 //若进度低于50,应选择当前颜色(成熟度较低的颜色) boolean getPresentColorFruit = systemTransition < 50; // --->我希望优化这段for-if-if-else-elseif-if-else逻辑 <--- for (FruitColor fruitColor : fruitColors) { //首先检查重复的FruitColor List<FruitColor> sameNameFruits = fruitColors.stream() .filter(fc -> fc.getFruit().getName().equals(itemColor.getFruit().getName())) .collect(Collectors.toList()); //若该果实仅存在一个条目,且未添加至结果列表,则按规则设置成熟度后添加 //factorialRipeness为“真实”成熟度 if (sameNameFruits.size() == 1 && !suggestedFruits.stream().anyMatch(fc -> fc.getFruit().getName().equals(sameNameFruits.get(0).getFruit().getName()))) { FruitColor onlyOne = sameNameFruits.get(0); if (onlyOne.getColor().getColorId() == presentColor.getColor().getColorId()) { onlyOne.setFactorialRipeness(onlyOne.getRipeness() * systemTransition); } else { onlyOne.setFactorialRipeness(onlyOne.getRipeness() * (100 - systemTransition)); } suggestedFruits.add(onlyOne); //若存在多个条目,需降低成熟度(此逻辑在示例实体中可能不合理,敬请谅解) } else if(!suggestedFruits.stream().anyMatch(fc -> fc.getFruit().getName().equals(sameNameFruits.get(0).getFruit().getName()))){ if (getPresentColorFruit) { FruitColor fcWithPresentColor = sameNameFruits.stream() .filter(fc -> fc.getColor().getColorId() == presentColor.getColor().getColorId()).findFirst() .get(); fcWithPresentColor.setFactorialRipeness((fcWithPresentColor.getRipeness() - 0.5) * systemTransition); suggestedFruits.add(fcWithPresentColor); } else { FruitColor fcWithFutureColor = sameNameFruits.stream() .filter(fc -> fc.getColor().getColorId() == futureColor.getColor().getColorId()).findFirst() .get(); //此逻辑也可能不合理,若未选择当前颜色,则需用100-systemTransition进行计算 fcWithFutureColor.setFactorialRipeness((fcWithFutureColor.getRipeness() - 0.5) * (100 - systemTransition)); suggestedFruits.add(fcWithFutureColor); } } } //按“真实”成熟度从低到高排序 Collections.sort(suggestedFruits, new FruitColorRipenessComparator()); return suggestedFruits; } /** * @source https://stackoverflow.com/questions/2839137/how-to-use-comparator-in-java-to-sort */ public class FruitColorRipenessComparator implements Comparator<FruitColor> { @Override public int compare(FruitColor a, FruitColor b){ return a.getFactorialRipeness() < b.getFactorialRipeness() ? -1 : a.getFactorialRipeness() == b.getFactorialRipeness() ? 0 : 1; } }
优化方案
1. 核心优化思路
- 先按
fruitName分组,避免循环中重复遍历整个列表 - 用HashSet记录已处理的果实名称,替代低效的stream判断
- 拆分逻辑为独立方法,提高代码可读性和可维护性
优化后的代码示例
// 方法内逻辑 { List<FruitColor> fruitColors = getAllFCs(); String presentColorId = presentColor.getColor().getColorId(); String futureColorId = futureColor.getColor().getColorId(); // 过滤仅保留指定两种颜色的条目 List<FruitColor> filtered = fruitColors.stream() .filter(fc -> presentColorId.equals(fc.getColor().getColorId()) || futureColorId.equals(fc.getColor().getColorId())) .collect(Collectors.toList()); // 按fruitName分组,一次操作完成所有分组 Map<String, List<FruitColor>> groupedByFruitName = filtered.stream() .collect(Collectors.groupingBy(fc -> fc.getFruit().getFruitName())); boolean choosePresent = systemTransition < 50; Set<String> processedFruits = new HashSet<>(); List<FruitColor> suggestedFruits = new ArrayList<>(); for (Map.Entry<String, List<FruitColor>> entry : groupedByFruitName.entrySet()) { String fruitName = entry.getKey(); if (processedFruits.contains(fruitName)) { continue; } processedFruits.add(fruitName); List<FruitColor> sameNameList = entry.getValue(); // 选择要保留的条目 FruitColor selected = selectTargetFruit(sameNameList, choosePresent, presentColorId, futureColorId); // 计算并设置成熟度 calculateFactorialRipeness(selected, sameNameList.size() > 1, systemTransition, presentColorId); suggestedFruits.add(selected); } // 用Lambda简化排序逻辑,替代自定义Comparator suggestedFruits.sort(Comparator.comparingDouble(FruitColor::getFactorialRipeness)); return suggestedFruits; } // 封装选择目标条目逻辑 private FruitColor selectTargetFruit(List<FruitColor> sameNameList, boolean choosePresent, String presentColorId, String futureColorId) { if (sameNameList.size() == 1) { return sameNameList.get(0); } // 按规则筛选目标颜色的条目,添加兜底避免空指针 return sameNameList.stream() .filter(fc -> choosePresent ? presentColorId.equals(fc.getColor().getColorId()) : futureColorId.equals(fc.getColor().getColorId())) .findFirst() .orElse(sameNameList.get(0)); } // 封装成熟度计算逻辑 private void calculateFactorialRipeness(FruitColor fruitColor, boolean hasDuplicate, double systemTransition, String presentColorId) { double baseRipe = hasDuplicate ? fruitColor.getRipe() - 0.5 : fruitColor.getRipe(); double multiplier = presentColorId.equals(fruitColor.getColor().getColorId()) ? systemTransition : (100 - systemTransition); fruitColor.setFactorialRipeness(baseRipe * multiplier); }
优化效果说明
- 性能提升:分组操作仅执行一次,将原O(n²)的时间复杂度降至O(n);HashSet判断已处理果实的时间复杂度为O(1),替代原O(n)的stream判断
- 代码简洁性:拆分逻辑到独立方法,主流程清晰易懂;用Stream API和Lambda简化过滤、排序逻辑
- 鲁棒性增强:添加
findFirst()的兜底处理,避免空指针异常;提取颜色ID常量,减少重复调用getter
内容的提问来源于stack exchange,提问作者zhrgci
相关产品推荐
相关产品推荐

