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

重构C# CSV解析器与数据聚合:字典排序及区域解析最佳实践

问题解答:优化C#电影数据CSV读取程序

一、解决区域适配问题:正确解析小数

直接替换小数点的方式依赖系统区域设置,风险极高。CSV文件的小数分隔符通常遵循不变文化(InvariantCulture)(即小数点为.),因此解析时应显式指定文化信息,无需手动替换字符:

  1. 添加命名空间:using System.Globalization;
  2. 修改Film构造函数中的小数解析代码:
// 替换原有的Replace方式
AtlagosJegyar = double.Parse(sor2[6], CultureInfo.InvariantCulture);

如果CSV文件的小数分隔符确实是逗号(如本地化CSV),可指定对应文化(如CultureInfo.GetCultureInfo("hu-HU")),但显式指定文化始终比字符替换更稳健。

二、用LINQ与现代.NET特性优化代码

1. 简化文件读取逻辑

原Beolvasas方法的循环可通过LINQ+File.ReadLines(延迟加载,内存效率更高)替换,一行完成数据读取、过滤和转换:

public static List<Film> Beolvasas(string fajlnev)
{
    return File.ReadLines(fajlnev)
               .Skip(1) // 跳过表头行
               .Where(line => !string.IsNullOrWhiteSpace(line))
               .Select(line => new Film(line))
               .ToList();
}

File.ReadLines相比ReadAllLines,不会一次性加载所有行到内存,适合处理大文件。

2. 简化Feladat6:计算平均观众数

原循环累加可通过LINQ的Average直接实现,代码更简洁:

static void Feladat6()
{
    double atlag = filmek.Average(f => f.Nezoszam);
    Console.WriteLine("6.feladat: A filmek átlagos nézőszáma {0:0.0} fő", atlag);
}

3. 用LINQ GroupBy彻底简化Feladat8:按类型统计观众数

完全无需手动填充Dictionary,GroupBy可直接按电影类型分组,对每组观众数求和后排序:

static void Feladat8()
{
    Console.WriteLine("8. feladat: Műfajok összesített nézőszáma:");
    var mufajStatisztika = filmek
        .GroupBy(f => f.Mufaj)
        .Select(g => new { Mufaj = g.Key, OsszNezoszam = g.Sum(f => f.Nezoszam) })
        .OrderByDescending(item => item.OsszNezoszam);

    foreach (var item in mufajStatisztika)
    {
        Console.WriteLine($"\t-  {item.Mufaj}: {item.OsszNezoszam} fő");
    }
}

这段代码逻辑清晰,避免了手动处理字典键的存在性判断,符合地道的C# LINQ风格。

三、完整优化后代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Globalization;

namespace filmapp
{
    internal class Film
    {
        public int Sorszam { get; set; }
        public string Cim { get; set; }
        public string Mufaj { get; set; }
        public int BemutatasiEv { get; set; }
        public string Rendezo { get; set; }
        public int Nezoszam { get; set; }
        public double AtlagosJegyar { get; set; }

        public Film(string sor)
        {
            string[] sor2 = sor.Split(';');

            Sorszam = int.Parse(sor2[0]);
            Cim = sor2[1];
            Mufaj = sor2[2];
            BemutatasiEv = int.Parse(sor2[3]);
            Rendezo = sor2[4];
            Nezoszam = int.Parse(sor2[5]);
            // 显式使用不变文化解析小数,避免区域问题
            AtlagosJegyar = double.Parse(sor2[6], CultureInfo.InvariantCulture);
        }

        public static List<Film> Beolvasas(string fajlnev)
        {
            return File.ReadLines(fajlnev)
                       .Skip(1)
                       .Where(line => !string.IsNullOrWhiteSpace(line))
                       .Select(line => new Film(line))
                       .ToList();
        }
    }

    internal class Program
    {
        static List<Film> filmek = new List<Film>();
        static void Main(string[] args)
        {
            Feladat4();
            Feladat5();
            Feladat6();
            Feladat7();
            Feladat8();
            Console.ReadKey();
        }

        static void Feladat4() => filmek = Film.Beolvasas("filmek.csv");

        static void Feladat5() => Console.WriteLine("5. feladat: {0} film található az állományban", filmek.Count);

        static void Feladat6()
        {
            double atlag = filmek.Average(f => f.Nezoszam);
            Console.WriteLine("6.feladat: A filmek átlagos nézőszáma {0:0.0} fő", atlag);
        }

        static void Feladat7()
        {
            Console.WriteLine("7. feladat: 2018 után megjelent, népszerű filmek:");
            foreach (var f in filmek.Where(x => x.Nezoszam > 1000000 && x.BemutatasiEv > 2018))
            {
                Console.WriteLine($"\t-{f.Cim} ({f.BemutatasiEv})");
            }
        }

        static void Feladat8()
        {
            Console.WriteLine("8. feladat: Műfajok összesített nézőszáma:");
            var mufajStatisztika = filmek
                .GroupBy(f => f.Mufaj)
                .Select(g => new { Mufaj = g.Key, OsszNezoszam = g.Sum(f => f.Nezoszam) })
                .OrderByDescending(item => item.OsszNezoszam);

            foreach (var item in mufajStatisztika)
            {
                Console.WriteLine($"\t-  {item.Mufaj}: {item.OsszNezoszam} fő");
            }
        }
    }
}

关键优化点总结

  • 区域适配:用CultureInfo.InvariantCulture显式解析小数,替代脆弱的字符替换
  • 文件IO:使用File.ReadLines实现延迟加载,提升大文件处理性能
  • LINQ简化:用GroupBy+Sum替代手动字典填充,用Average替代循环累加,代码更简洁易读
  • 类型转换:用int.Parse替代Convert.ToInt32,语义更明确(已知输入为有效整数时)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 02:27:29