Map中Activity费用求和错位修复及活动名称关联展示方案
解决你的两个问题:数值错位与活动名称+费用的存储
一、先搞定数值错位的问题
你的代码返回的列表数值错位,大概率是两个原因导致的,咱们一个个说:
1. HashMap的无序性坑了你
如果allActiv是用HashMap<String, Activity>存储的,那遍历values()的顺序是不固定的,完全不遵循你添加活动的顺序。你以为第一个位置对应第一个添加的活动,但HashMap可能把它放到了后面,自然数值就错位了。
解决办法:
- 把
allActiv改成LinkedHashMap<String, Activity>,它会严格保留你添加元素的顺序; - 如果需要按特定规则排序(比如活动名称、创建时间),可以把
allActiv.values()转成List后手动排序:List<Activity> sortedActivities = new ArrayList<>(this.allActiv.values()); // 按活动名称升序排序 Collections.sort(sortedActivities, Comparator.comparing(Activity::getName));
2. Activity的equals方法没重写
你的代码里用e.getActivity().equals(a)判断费用属于哪个活动,但如果Activity类没重写equals,默认会比较对象引用。举个例子:从数据库加载的Activity实例,和Expense里关联的Activity实例,哪怕属性完全一样,只要不是同一个对象,equals就会返回false,导致费用匹配错误,数值自然就对不上。
解决办法:在Activity类里重写equals和hashCode,用活动的唯一标识(比如id)来判断相等:
import java.util.Objects; public class Activity { private String id; // 活动唯一ID private String name; // 其他属性... @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Activity activity = (Activity) o; return Objects.equals(id, activity.id); } @Override public int hashCode() { return Objects.hash(id); } // Getters & Setters... }
二、同时存储活动名称和总费用的解决方案
ArrayList只能存单一类型,咱们有两种靠谱的方案:
方案1:自定义一个汇总类(推荐,可读性最强)
创建一个专门的DTO(数据传输对象),用来封装活动名称和对应的总费用:
public class ActivityExpenseSummary { private String activityName; private double totalExpense; // 构造方法 public ActivityExpenseSummary(String activityName, double totalExpense) { this.activityName = activityName; this.totalExpense = totalExpense; } // Getters public String getActivityName() { return activityName; } public double getTotalExpense() { return totalExpense; } // 可选:重写toString方便调试 @Override public String toString() { return activityName + ": " + totalExpense; } }
方案2:用Java自带的Entry类(快速实现)
如果不想写自定义类,可以用AbstractMap.SimpleEntry,它自带键值对的结构:
// 返回类型改成ArrayList<AbstractMap.SimpleEntry<String, Double>> AbstractMap.SimpleEntry<String, Double> entry = new AbstractMap.SimpleEntry<>(a.getName(), totalAct);
优化后的完整代码
结合上面的修复,我把你的代码重构了一下,不仅解决了问题,还提升了效率(原来的代码是O(M*N)的时间复杂度,现在是O(M+N),数据量大的时候差别很大):
import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class YourClassName { // 替换成你的类名 private Map<String, Activity> allActiv; private Map<String, Expense> expenses; private String userId; // 其他属性和方法... public ArrayList<ActivityExpenseSummary> getValueForActivity() { ArrayList<ActivityExpenseSummary> summaryList = new ArrayList<>(); // 第一步:先统计当前用户所有费用的活动分组,只遍历一次expenses Map<Activity, Double> activityTotalMap = new HashMap<>(); for (Expense e : expenses.values()) { if (userId.equals(e.getCustomerId())) { Activity activity = e.getActivity(); // 累加费用,没有记录的话初始化为0 double currentTotal = activityTotalMap.getOrDefault(activity, 0.0); activityTotalMap.put(activity, currentTotal + e.getExpenseValue()); } } // 第二步:遍历所有活动,生成汇总列表(如果用LinkedHashMap则顺序和添加一致) for (Activity a : allActiv.values()) { double totalAct = activityTotalMap.getOrDefault(a, 0.0); summaryList.add(new ActivityExpenseSummary(a.getName(), totalAct)); } return summaryList; } }
最后再提醒一下
如果用了上面的优化代码,一定要确保Activity类重写了equals和hashCode,否则activityTotalMap里的键值匹配会出问题哦!
内容的提问来源于stack exchange,提问作者John Mulaney
相关产品推荐
相关产品推荐

