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

C# 从TXT读数据 用Dictionary按年、月维度填充DataGridView的实现求助

核心实现方案

你考虑的Dictionary<int, Dictionary<int, int>>结构完全适配动态年份的需求,Dictionary本身就是动态键值存储结构,不需要提前枚举所有可能的年份,运行时读到哪年的记录就自动新增对应条目,根本不会因为年份不确定卡壳。

逻辑拆解

  • 替换单层汇总字典为嵌套结构
    外层Dictionary的键存储动态出现的年份,值为内层Dictionary;内层Dictionary的键存储1-12月的月份值,值为对应年月下num1的累计汇总值。
  • 逐行处理记录时按年-月双层累加
    每读到一条Record对象,同时取出对应日期的年份和月份,按两层键的层级判断是否存在对应条目,不存在则初始化,存在则累加num1值,逻辑和你之前实现的单月汇总完全一致,只是多了一层按年份的拆分。
  • 按固定列结构填充DataGridView
    dgv的列结构是固定的(第一列Y,后接12个月份列),行是动态的:遍历所有收集到的年份,按升序排序后逐行添加,每个月份列如果没有对应汇总值就填充0,避免出现空单元格。

修正后的可运行代码

替换原有逻辑即可,顺带修正原代码里未定义变量m的问题,去掉了容易出边界bug的字符串拼接拆分逻辑:

private void Form_Load(object sender, EventArgs e)
{
    // 嵌套字典:外层key=年份,内层key=月份,value=对应num1汇总值
    Dictionary<int, Dictionary<int, int>> dataByYearMonth = new Dictionary<int, Dictionary<int, int>>();
    Record b;

    try
    {
        if (File.Exists("data.txt"))
        {
            using (StreamReader sr = new StreamReader("data.txt"))
            {
                while (!sr.EndOfStream)
                {
                    b = new Record(sr.ReadLine());
                    int year = b.date1.Year;
                    int month = b.date1.Month;

                    // 第一层:判断是否存在当前年份的条目
                    if (!dataByYearMonth.ContainsKey(year))
                    {
                        // 新年份直接初始化内层空字典
                        dataByYearMonth[year] = new Dictionary<int, int>();
                    }
                    // 拿到当前年份对应的月份字典
                    var monthDict = dataByYearMonth[year];
                    // 第二层:判断是否存在当前月份的条目,逻辑和原有单月汇总完全一致
                    if (!monthDict.ContainsKey(month))
                    {
                        monthDict[month] = b.num1;
                    }
                    else
                    {
                        monthDict[month] += b.num1;
                    }
                }
            }

            // 清空dgv原有行,避免重复加载
            dgv.Rows.Clear();
            // 对收集到的年份按升序排序,避免Dictionary随机存储顺序导致行序混乱
            var sortedYears = dataByYearMonth.Keys.OrderBy(y => y).ToList();
            foreach (int year in sortedYears)
            {
                // 构建13个元素的行数组,匹配dgv的1列年份+12列月份结构
                var rowValues = new object[13];
                rowValues[0] = year;
                // 按固定顺序填充1-12月的汇总值,无数据则填0
                for (int m = 1; m <= 12; m++)
                {
                    rowValues[m] = dataByYearMonth[year].TryGetValue(m, out int val) ? val : 0;
                }
                dgv.Rows.Add(rowValues);
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"数据加载失败:{ex.Message}");
    }
}

开发注意点

  • 不需要提前给每个年份预生成12个月份的条目,在填充行时通过TryGetValue判断是否有对应月份数据即可,无数据自动填0,能减少不必要的内存占用。
  • 填充行前一定要对年份键做排序,否则Dictionary的键存储顺序是哈希随机的,会导致dgv里的年份行顺序混乱,不符合常规阅读习惯。
  • 原代码里拼接字符串拆分数组的方法容易出现边界问题(比如末尾多拼接的下划线会拆分出空字符串、字典遍历顺序和12个月的列顺序不匹配),直接按1-12月的固定顺序取值填充,能保证列和值严格对应。
  • 如果后续需要扩展其他字段的汇总,只需要在内层结构里新增对应键值即可,不需要改动外层的动态年份逻辑。

内容的提问来源于stack exchange,提问作者Alan Romagnoli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 17:36:04