C#循环遍历两个列表,从列表#2中删除重复项

时间:2014-08-05 16:23:16

标签: c# arrays list

我有一个目录的文件名(aryFileNames)数组。我有一个CSV文件的文件名列表(lstKeepers)。此列表是SUPPOSED在目录中的文件列表。我实际上在做的是在目录中查找孤立文件。

我现在已经重复了这个逻辑3次,每当我最终遇到需要重新修改它的碰撞时,所以我只是想弄清楚我应该如何处理它。

我目前的逻辑是:

List<string> lstKeepers = new List<string>(aryKeepers);
DirectoryInfo dir = new DirectoryInfo(txtMSALoc.Text);
FileInfo[] attFiles = dir.GetFiles();
//variable for testing if a keeper was found.
bool bolTest = false;
//Loop through the directory's files
foreach (FileInfo attFile in attFiles)
{
    //Loop through the list of keepers
    foreach (string lstKeeper in lstKeepers){
        if (lstKeeper == attFile.Name)
        {
            //This file is a keeper not an orphan, remove it from the list.
            // This line doesn't actually work.  Is a List the right way to go?
            lstKeepers(lstKeeper).remove;
            bolTest = true;
            break;
        }
    }
    // Code fell out of the loop, see if it found a keeper.
    if (bolTest)
    {
        bolTest=false;
    }
    else
    {
        //CODE TO MOVE FILE INTO ORPHAN DIRECTORY
    }
}

我正在处理多达200万个文件的潜在目录(和守护者列表),这就是我希望用它找到的每个文件来缩小守护者列表的原因,所以应该去它运行的时间越长越快。

所以我的第一个问题是,有没有更好的方法呢?

我的下一个问题是,数组和列表是最好用的吗?当你需要删除东西时,我看到了一些关于链表更好的东西。

这里简要介绍了我之前尝试过的内容:

1)同时循环浏览目录列表和守护列表: 因为两者都是大多数文件的数值.file = 123,file.name = 124等等,我只是比较文件名的值,并根据当前对是否&lt;来确定要采取的行动。或者&gt;彼此或=。但是由于缺乏自然分类,这没有用。

2)仅使用两个数组,但从数组中删除项目并不实际(因为我必须继续重新创建数组)。

3)(当前)这似乎是我可以删除项目的方式,但有人说使用LinkedLists删除项目,因为我厌倦了重新启动这个项目,这是破坏编码器和#39; s回来:))

感谢任何建议!

更新:这是最终版本,非常感谢大家的帮助!

            string[] aryKeepers;
            if (File.Exists("Keepers.csv"))
            {
                aryKeepers = File.ReadAllLines("Keepers.csv");
            }
            else
            {
                MessageBox.Show("Cannot find 'Keepers.csv' file.", "Missing CSV File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                aryKeepers = null;
                return;
            }
            List<string> lstKeepers = new List<string>(aryKeepers);
            DirectoryInfo dir = new DirectoryInfo(txtMSALoc.Text);
            FileInfo[] attFiles = dir.GetFiles();
            List<string> lstOrphans = attFiles
                                        .Where(x => !lstKeepers.Contains(x.Name))
                                        .Select(x => x.Name)
                                        .ToList();
            if (lstOrphans.Count > 0){
                intOrphan = lstOrphans.Count;
                lstOrphans.ForEach (lstOrphan => {
                    string strOldFile = txtMSALoc.Text + @"\" + lstOrphan;
                    string strNewFile = dirOrphan + lstOrphan;
                    File.Move(strOldFile, strNewFile);
                });
            }

3 个答案:

答案 0 :(得分:4)

为什么不

List<string> orphans = new List<string>();

// Enumerate files in directory
foreach(string file in attFiles)
{
    // If the filename isn't in the keepers list it must be 
    // an orphan, add it to the orphans list
    if(!lstKeepers.Contains(file.Name))
        orphans.Add(file.Name);
}

之后

foreach(string orphanedFile in orphans)
{ 
    // Move the file
}

我不认为它会有惊人的表现,但你没有提到性能问题 - 只是你无法使逻辑正确

我还可以补充一点,尝试在列举项目时从列表中删除项目(即foreach循环)将导致运行时异常,这可能是您遇到的问题之一

编辑:只是为了好玩,因为每个人都喜欢linq(因为gunr2171建议了)

List<string> orphans = attFiles
                            .Where(x => !lstKeepers.Contains(x.Name))
                            .Select(x => x.Name)
                            .ToList();

然后你可以

orphans.ForEach(orphan => { // Do something });

答案 1 :(得分:3)

您可以将文件名放在HashSet<string>中以便快速查找,然后循环浏览那里找到的文件:

FileInfo[] attFiles = new DirectoryInfo(txtMSALoc.Text).GetFiles();
HashSet<string> att = new HashSet<string>(attFiles.Select(a => a.Name));
foreach (string attFile in aryKeepers.Where(s => att.Contains(s))) {
  //CODE TO MOVE FILE INTO ORPHAN DIRECTORY
}

答案 2 :(得分:2)

您可以使用HashSet代替列表,因为它会为Contains提供O(1) performance与使用List<T>的O(n)效果。 Remove性能也非常好,因此您的代码可以简化为:

HashSet<string> lstKeepers = new HashSet<string>(aryKeepers);
DirectoryInfo dir = new DirectoryInfo(txtMSALoc.Text);
FileInfo[] attFiles = dir.GetFiles();

//Loop through the directory's files
foreach (FileInfo attFile in attFiles)
{
    if (lstKeepers.Contains(attFile.Name))
    {
        //CODE TO MOVE FILE INTO ORPHAN DIRECTORY

        //remove from the HashSet
        lstKeepers.Remove(attFile.Name);
    }
}