You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:24:08