你是不是也经常遇到这种烦心事:打开一个 Excel 表格,里面乱七八糟一大堆,光重复的数据就占了一半?无论是做数据清洗、出报表,还是搞分析,去重几乎是逃不掉的“必修课”。今天咱就聊聊怎么用 Free Spire.XLS for .NET 这个免费组件(不用装 Office ),几行 C# 代码就把重复行安排得明明白白。


实现思路

先理清楚核心逻辑,弄懂原理再写代码会更轻松:

  1. 选好关键列——比如按 A 列的值判断是否重复。
  2. 遍历数据,把相同值的行归到一组。
  3. 每组里只留第一行(索引最小的),其他的统统记下来。
  4. 从后往前删掉这些“多余”的行,避免删着删着索引乱套。

简单说:分组→保留第一个→删后面的


准备工作

打开你的项目,在 NuGet 里搜一下 FreeSpire.XLS 这个包并安装,或直接使用:

Install-Package FreeSpire.XLS

这款免费组件足以应对绝大多数中小型项目的数据处理需求。


分步代码解析

下面咱们一步步拆解代码,边写边理解。假设本地有一份 Test.xlsx 文件,A 列存在大量重复数据,我们要保留首次出现的行,删掉后续所有重复行。

1. 加载文件,拿到工作表

using Spire.Xls;
using System.Linq;

Workbook workbook = new Workbook();
workbook.LoadFromFile("Test.xlsx");

Worksheet sheet = workbook.Worksheets[0];

2. 确定数据范围

sheet.LastRow 拿到最后有数据的行,构造一个从 A1 到 A 列末尾的范围。如果你想跳过表头,把 A1 改成 A2 就行。

var range = sheet.Range[$"A1:A{sheet.LastRow}"];

3. 找出需要删除的重复行号

用 LINQ 极简实现分组筛选,省去手写循环的繁琐。

这里特意提一句:优先用 DisplayedText,它能拿到单元格最终展示效果,适配格式、公式计算值,比单纯取 Value 靠谱得多,能避免很多莫名的判重错误。

var duplicatedRows = range.Rows
    .GroupBy(row => row.Columns[0].DisplayedText)   // 按 A 列显示的内容分组
    .Where(group => group.Count() > 1)             // 只要有重复的分组
    .SelectMany(group => group.Skip(1))            // 跳过每组第一个,剩下的就是要删的
    .Select(row => row.Columns[0].Row)             // 取出这些行的行号
    .ToList();

简单梳理下这段代码的逻辑:按单元格内容分组后,只保留有重复的组,每组跳过第一条,剩下的就是我们要删掉的行。

4. 删除重复行

直接按行号正着删,后面的行号会变,容易删错。所以咱们从后往前删,或者动态调整索引。下面两种写法都可以:

方式一:倒序删(推荐,易懂)

foreach (int rowNum in duplicatedRows.OrderByDescending(r => r))
{
    sheet.DeleteRow(rowNum);
}

方式二:循环里减 i

for (int i = 0; i < duplicatedRows.Count; i++)
{
    sheet.DeleteRow(duplicatedRows[i] - i);
}

5. 保存结果

处理完成后,直接导出新文件,还能自由指定 Excel 版本格式:

workbook.SaveToFile("RemoveDuplicateRows.xlsx");

完整代码示例

整合所有步骤,直接复制到控制台项目就能运行测试:

using Spire.Xls;
using System.Linq;

namespace RemoveDuplicateRows
{
    class Program
    {
        static void Main(string[] args)
        {
            Workbook workbook = new Workbook();
            workbook.LoadFromFile("Test.xlsx");

            Worksheet sheet = workbook.Worksheets[0];
            var range = sheet.Range[$"A1:A{sheet.LastRow}"];

            var duplicatedRows = range.Rows
                .GroupBy(x => x.Columns[0].DisplayedText)
                .Where(x => x.Count() > 1)
                .SelectMany(x => x.Skip(1))
                .Select(x => x.Columns[0].Row)
                .ToList();

            // 从后往前删,稳稳的
            foreach (int rowNum in duplicatedRows.OrderByDescending(r => r))
            {
                sheet.DeleteRow(rowNum);
            }

            workbook.SaveToFile("RemoveDuplicateRows.xlsx");
        }
    }
}

几个你可能关心的小细节

想按多列判断重复?改一下 GroupBy 就行

比如 A 列和 B 列都相同才算重复:

.GroupBy(row => new { 
    Col1 = row.Columns[0].DisplayedText, 
    Col2 = row.Columns[1].DisplayedText 
})

第一行是表头,不想删它?

那就从 A2 开始取范围:

var range = sheet.Range[$"A2:A{sheet.LastRow}"];

别忘了释放资源

Workbook 实例使用完后,建议手动释放资源,或者用 using 语句包裹,避免程序长时间运行造成内存堆积。

using (Workbook workbook = new Workbook())
{
    // 你的代码
}

整体看下来,这套方案上手简单、适配性强,既能满足单列、多列去重,也能适配带表头的业务表格。把这段代码稍作封装,就能直接用到日常数据自动化、后台报表生成等场景里,省去大量手动处理表格的重复工作。

更多推荐