如何以编程方式在多个工作表之间的 Excel 单元格中查找重复值

How to find duplicate values in Excel cells between multiple sheets programmatically

例如,我有一个名为 EmployeeSheet 的 sheet,它只是公司中每位员工姓名的一列。并且假设此列表格式正确并且没有重复项,因此此 sheet 中的每个单元格都是唯一的。

现在我公司每个部门都有一个sheet,比如FinanceSheetITSheet销售表。每个 sheet 在某处(因为每个 sheet 没有相同的布局)每个部门的员工列表。但是,任何 1 个员工姓名 应该 只在所有部门 sheet 之间出现一次(这不包括 EmployeeSheet)。

这是我能想到但不知道如何实现的解决方案,那就是制作一个多维数组(在学校学过一点点,但依稀记得如何使用)。

伪代码类似于:

 arrEmployees = {"Tom Hanks", "Burt Reynolds", "Your Mom"}
 arrFinance = {"Tom Hanks"}
 arrIT = {"Burt Reynolds"}
 arrSales = {"Your Mom"}
 arrSheets = {arrEmployees, arrFinance, arrIT, arrSales}

虽然我已经能够通过使用

获取单个单元格值和范围作为字符串
Sheets shts = app.Worksheets;
Worksheet ws = (Worksheet)sheets.get_Item("EmployeeSheet");
Excel.Range empRange = (Excel.Range)worksheet.get_range("B2");
string empVal = empRange.Value2.ToString();  

但是通过将单个单元格值获取到字符串的过程,我不知道如何将其放入数组的元素中,更不用说值的范围了。

我确信我的方法不是最有效的,甚至可能不可能,但这就是我来这里寻求帮助的原因,所以任何提示都将受到赞赏。


编辑:这是最终为我工作的解决方案。感谢 Ian Edwards 解决方案。

Dictionary<string, List<Point>> fields = new Dictionary<string, List<Point>>();
fields["Finance"] = new List<Point>() { new Point(2,20)};
fields["Sales"] = new List<Point>();
for (int row = 5; row <= 185; row += 20) {fields["Sales"].Add(new Point(2,row));}

List<string> names = new List<string>();
List<string> duplicates = new List<string>();
foreach (KeyValuePair<string, List<Point>> kp in fields)
{ 
   Excel.Worksheet xlSheet = (Excel.Worksheet)workbook.Worksheets[kp.Key];
   foreach (Point p in kp.Value)
   {
     if ((xlSheet.Cells[p.Y, p.X] as Excel.Range.Value != null)
     {
       string cellVal = ((xlSheet.Cells[p.Y,p.X] as Excel.Range).Value).ToString();
       if (!names.Contains(cellVal))
       { names.Add(cellVal)) }
       else { duplicates.Add(cellVal); } } } }
  1. 您可以使用.Range定义多个单元格(即.Range["A1", "F500"]

https://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.worksheet.range.aspx

  1. 然后您可以使用 .get_Value 获取该范围内所有单元格的 contents/values。根据 dotnetperls.com get_Value() is much faster than get_Range()(参见 'Performance' 部分)。使用多个范围 + get_value 的组合 肯定会 比使用 get_range.
  2. 的许多单一范围调用表现更好

https://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.namedrange.get_value(v=vs.120).aspx

我将它们存储在 Object Array.

(object[,])yourexcelRange.get_Value(Excel.XlRangeValueDataType.xlRangeValueDefault);

从那里您可以编写自己的比较方法来比较多个数组。一个怪癖是这样做 returns 一个索引为 1 的数组,而不是标准的基于 0 的索引。

这是我拼凑的一个小例子 - 评论应该逐行解释发生了什么。

您可以声明要检查姓名的工作表的名称,以及在 'worksheets' 字典中从何处开始查找姓名。

我假设您不知道每个列表中有多少个名字 - 它会继续向下移动每个列表,直到遇到空白单元格。

        // Load the Excel app
        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
        // Open the workbook
        var xlWorkbook = xlApp.Workbooks.Open("XLTEST.xlsx");

        // Delcare the sheets and locations to look for names
        Dictionary<string, Tuple<int, int>> worksheets = new Dictionary<string, Tuple<int, int>>()
        {
            // Declare the name of the sheets to look in and the 1 base X,Y index of where to start looking for names on each sheet (i.e. 1,1, = A1)
            { "Sheet1", new Tuple<int, int>(1, 1) },
            { "Sheet2", new Tuple<int, int>(2, 3) },
            { "Sheet3", new Tuple<int, int>(4, 5) },
            { "Sheet4", new Tuple<int, int>(2, 3) },
        };

        // List to keep track of all names in all sheets
        List<string> names = new List<string>();
        // Iterate over every sheet we need to look at
        foreach(var worksheet in worksheets)
        {
            string workSheetName = worksheet.Key;
            // Get this excel worksheet object
            var xlWorksheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkbook.Worksheets[workSheetName];
            // Get the 1 based X,Y cell index
            int row = worksheet.Value.Item1;
            int column = worksheet.Value.Item2;
            // Get the string contained in this cell
            string name = (string)(xlWorksheet.Cells[row, column] as Microsoft.Office.Interop.Excel.Range).Value;
            // name is null when the cell is empty - stop looking in this sheet and move on to the next one
            while(name != null)
            {
                // Add the current name to the list
                names.Add(name);
                // Get the next name in the cell below this one
                name = (string)(xlWorksheet.Cells[++row, column] as Microsoft.Office.Interop.Excel.Range).Value;
            }
        }
        // Compare the number of names to the number of unique names
        if (names.Count() != names.Distinct().Count())
        {
            // You have duplicate names!
        }