循环遍历两个列表,从列表#2中删除重复项
本文关键字:列表 删除 循环 两个 遍历 | 更新日期: 2023-09-27 18:16:43
我有一个目录的文件名数组(aryfilename)。我有一个CSV文件的文件名列表(lstKeepers)。这个列表是目录中应该包含的文件的列表。我所做的就是在目录中查找孤儿文件。
我已经重做了这个逻辑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万个文件的潜在目录(和看守列表),所以这就是我想用它找到的每个文件不断缩小看守列表的原因,所以它运行的时间应该越长越快。
所以我的第一个问题是,有没有更好的方法来做到这一点?
我的下一个问题是,数组和列表是最好的东西吗?当你需要删除一些内容时,我发现linkedlist会更好。
以下是我之前的尝试:1)同时循环遍历目录列表和keeper列表:由于两者在很大程度上都是数值file.name = 123, file.name = 124等等,我只是比较了文件名的值,并根据当前对是否为<或> each other或=。但由于缺乏自然排序,这不起作用。或>
2)只使用两个数组,但是从数组中删除项是不实际的(因为我必须不断重新创建数组)。
3)(目前)这似乎是我可以删除项目的方式,但后来有人说要使用LinkedLists来删除项目,因为我厌倦了重新启动这个项目,这是打破编码员背部的稻草:)
任何建议都是感激的!
更新:这是最终版本,非常感谢大家的帮助!
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);
});
}
为什么不直接
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 });
您可以将文件名放在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
}
您可以使用HashSet
代替列表,因为它将为Contains
提供O(1)性能,而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);
}
}