查找System.Array中是否存在任何元素,如果存在则从原始元素中删除

时间:2013-04-14 18:34:15

标签: c# arrays string-comparison

我有三个System.Array,我基本上存储了10个字符的电话号码。定义如下:

private static System.Array objRowAValues;
private static System.Array objRowBValues;
private static System.Array objRowCValues;

我这样做是因为我读了一个包含许多单元格(大约1 000 000)的巨大Excel文件,并且使用List<string>的进程有点慢。稍后在我的代码中,我将System.Array更改为List<string>,主要是因为我填充了ListBox元素。这些是List

的定义
private List<string> bd = new List<string>();
private List<string> bl = new List<string>();
private List<string> cm = new List<string>();

我想检查objRowBalues或objRowCValues中是否存在objRowAValues中的任何值,如果存在则删除现有值,我该怎么做?我是C#的新手,这是我的第一步。

编辑:这是我正在做的代码(仅限相关部分):

private List<string> bd = new List<string>();
private static System.Array objRowAValues;

private List<string> bl = new List<string>();
private static System.Array objRowBValues;

private List<string> cm = new List<string>();
private static System.Array objRowCValues;

private List<string> pl = new List<string>(); 

private static Microsoft.Office.Interop.Excel.Application appExcel;

Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.Range rngARowLast, rngBRowLast, rngCRowLast;

long lastACell, lastBCell, lastCCell, fullRow;

// this is the main method I use to load all three Excel files and fill System.Array and then convert to List<string>

private void btnCargarExcel_Click(object sender, EventArgs e)
    {
        if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            if (System.IO.File.Exists(openFileDialog1.FileName))
            {
                Stopwatch stopWatch = new Stopwatch();
                stopWatch.Start();
                Thread.Sleep(10000);

                filePath.Text = openFileDialog1.FileName.ToString();

                xlApp = new Microsoft.Office.Interop.Excel.Application();
                xlWorkBook = xlApp.Workbooks.Open(openFileDialog1.FileName, 0, true, 5, "", "", true,
                                                  Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false,
                                                  false, 0, true, 1, 0);
                xlWorkSheet = (Excel.Worksheet) xlWorkBook.Worksheets.get_Item(1);

                fullRow = xlWorkSheet.Rows.Count;
                lastACell = xlWorkSheet.Cells[fullRow, 1].End(Excel.XlDirection.xlUp).Row;
                rngARowLast = xlWorkSheet.get_Range("A1", "A" + lastACell);
                objRowAValues = (System.Array) rngARowLast.Cells.Value;

                foreach (object elem in objRowAValues) { bd.Add(cleanString(elem.ToString(), 10)); }

                nrosProcesados.Text = bd.Count().ToString();
                listBox1.DataSource = bd;

                xlWorkBook.Close(true, null, null);
                xlApp.Quit();

                releaseObject(xlWorkSheet);
                releaseObject(xlWorkBook);
                releaseObject(xlApp);

                stopWatch.Stop();

                TimeSpan ts = stopWatch.Elapsed;
                executiontime.Text =
                    String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds,
                                  ts.Milliseconds/10).ToString();
            }
            else
            {
                MessageBox.Show("No se pudo abrir el fichero!");
                System.Runtime.InteropServices.Marshal.ReleaseComObject(appExcel);
                appExcel = null;
                System.Windows.Forms.Application.Exit();
            }
        }
    }

    // This is the method where I clean the existent values from bd (the List where I should remove existent values on bl and existent values on cm
   private void btnClean_Click(object sender, EventArgs e)
    {
        pl = bd;
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        Thread.Sleep(10000);

        pl.RemoveAll(element => bl.Contains((element)));
        pl.RemoveAll(element => cm.Contains((element)));

        textBox2.Text = pl.Count.ToString();
        listBox4.DataSource = pl;

        stopWatch.Stop();

        TimeSpan ts = stopWatch.Elapsed;
        textBox6.Text =
            String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds,
                          ts.Milliseconds / 10).ToString();

    }

4 个答案:

答案 0 :(得分:1)

实际上有两个问题:

  1. 如何以性能有效的方式查找(巨大的)集合中存在的值?
  2. 如何从正在枚举的集合中删除值?
  3. 对于第一个,我建议使用HashSet作为Contains操作,因为List / Array需要O(1)而不是O(n)。

    第二个有点棘手 - 而不是迭代第一个集合,你可以遍历其余部分,只是尝试从第一个集合中删除这些项目。

    如果是Hashset,则Remove包含Contains逻辑并返回bool以指示值是否在收集中,因此使用HashSet更容易第一集也。

    所以看起来应该是这样的:

        var a = new HashSet<string>();
    
        // OR, if you have existing array:
        // var a = new HashSet<string>(myArray);
    
        var b = new HashSet<string>();
        var c = new HashSet<string>();
    
        // ... some filling logic here ...
    
        foreach (var item in b)
        {
            a.Remove(item);
        }
    
        foreach (var item in c)
        {
            a.Remove(item);
        }
    

    之后,您可以使用ToList()将值绑定到控件 - 它将创建包含所有未删除值的新数组:

        List<string> aList = a.ToList();
    

答案 1 :(得分:0)

根据对OP的评论,以下是您想要做的事情:

...make your lists...
bd.removeAll(phoneNum => bl.contains(phoneNum) || cm.contains(phoneNum));

请注意,不应使用arrays。您应该而是使用List<string>来完成上述所有这三项操作。

答案 2 :(得分:0)

假设它们是List并且您只想在bd中丢弃元素,因为您没有清楚地说明应删除哪些列表,我会这样做:

bd.RemoveAll(element => bl.Contains((element)));
bd.RemoveAll(element => cm.Contains((element)));

或者您可以尝试使用HashSet

private List<string> hsA = new List<string>();
private List<string> hsB = new List<string>();
private List<string> hsC = new List<string>();

尝试使用相同的方法:

hsA.RemoveWhere(element => hsB.Contains(element) || hsC.Contains(element));

答案 3 :(得分:0)

首先,如果您知道有多少行尝试使用适当的最大大小初始化List。所以它不必不断调整底层数组的大小。或者使用类型保存数组string[]来节省铸造等方面的麻烦。

如果您想过滤RowAValues列表,可以使用Linq:

rowAValues = rowAValues.Where(x => !rowBValues.Contains(x) 
                                && !rowCValues.Contains(x))
                       .ToArray()

如果您使用的是课程列表,请将ToArray替换为ToList。

请记住,迭代数千个项目是非常高性能的。如果多次执行检查,请考虑对行b + c使用HashSet<string>。代码保持不变,但查找速度很快。

LINQ(语言集成查询)的一个很好的参考是http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b