C# 提高列表中匹配字符串的速度

C# 提高列表中匹配字符串的速度,c#,lambda,matching,C#,Lambda,Matching,我有>20MB的文本文件,其中一些行在某些位置包含*。因此,应从此文件中删除与包含*的位置匹配的位置(例如700670*应导致删除所有位置70067000000到70067099999)。首先,我列出了要删除代码的位置: Parallel.ForEach(List, (pos) => { if (pos.IndexOf("*") != -1) { var lineWithStar = pos.Substring(0, pos.IndexOf("*")); var result =

我有>20MB的文本文件,其中一些行在某些位置包含*。因此,应从此文件中删除与包含*的位置匹配的位置(例如700670*应导致删除所有位置70067000000到70067099999)。首先,我列出了要删除代码的位置:

Parallel.ForEach(List, (pos) =>
{ if (pos.IndexOf("*") != -1)
 { var lineWithStar = pos.Substring(0, pos.IndexOf("*"));
    var result = from single in List 
    where single.Substring(0, lineWithStar.Length) == lineWithStar
    select single;
    listWithPositionsToDel.AddRange(result.Skip(1).ToList());
  }
});
要花很长时间才能得到结果

我需要从输入文件中删除行“123456”-匹配123*的所有内容

123*

123456

1245
123*

123456

1245

例如。 结果应该如下所示: 700204* 700205100614136* 700205100662305* 7002051006623443904 700205100667271* 700205120015472* 资料来源是: 700204* 700205100614136* 7002041232323234332 700205100662305* 7002051006141362332 7002051006623443904 700205100667271*
700205120015472

您有嵌套循环,这会影响您的性能。此外,您正在执行大量额外的字符串和列表分配

我会这样做:检查文件一次,找到所有需要删除的模式。然后再迭代一次,对于每一行,立即决定是否需要删除该行或保留该行。然后,您可以创建包含需要保留的行的新列表,或者直接写入新文件,或者只在单独的集合中添加要删除的项。诸如此类

var linePatternsToRemove = new List<String>();
var resultList = new ConcurrentBag<String>();
foreach (var line in List)
{
    var asteriskIndex = line.IndexOf("*");
    if (asteriskIndex != -1)
    {
        linePatternsToRemove.Add(line.Substring(0, asteriskIndex));
    }
}

Parallel.ForEach(List, currentLine =>
{
    Boolean needDeleteLine = false;
    foreach (var pattern in linePatternsToRemove)
    {
        if (currentLine.StartsWith(pattern))
        {
            // If line starts with pattern like "700204" it may be the pattern line itself "700204*" and we don't need to delete it
            // or it can be regular line and we like "70020412" and we need to delete it.
            if (currentLine.Length > pattern.Length && currentLine[pattern.Length] != '*')
            {
                needDeleteLine = true;
                break;
            }
        }
    }
    if (!needDeleteLine)
        resultList.Add(currentLine);
});
var linePatternsToRemove=new List();
var resultList=新的ConcurrentBag();
foreach(列表中的var行)
{
var asteriskIndex=第行IndexOf(“*”);
如果(星号Kindex!=-1)
{
linePatternsToRemove.Add(line.Substring(0,asteriskIndex));
}
}
Parallel.ForEach(列表,currentLine=>
{
布尔值needDeleteLine=false;
foreach(linePatternsToRemove中的变量模式)
{
if(当前线路启动(模式))
{
//如果线条以“700204”这样的图案开头,它可能是图案线条本身“700204*”,我们不需要删除它
//或者它可以是常规行,我们喜欢“70020412”,我们需要删除它。
如果(currentLine.Length>pattern.Length&¤tLine[pattern.Length]!=“*”)
{
needDeleteLine=true;
打破
}
}
}
如果(!needDeleteLine)
结果列表添加(当前行);
});
更新:可能你不需要并行。Foreach和plainsimplefor循环将足够快。但如果您需要并行,您应该考虑线程安全的结果收集

Update2:对代码进行更改以反映新信息。请注意,当使用并行循环时,输出结果收集将发生故障。此外,性能在很大程度上取决于文件中模式的数量。如果您有大量的模式,则需要更复杂的解决方案来针对大量不同的模式测试每一行。在这种情况下,使用树可能是一个不错的选择。

我需要从输入文件中删除行“123456”——所有匹配123*的内容

123*

123456

1245

你怎么看这个文件的?我猜是读到记忆里了?那么你还在记忆中复制第二份?您最好是读入行并写入新文件以替换它,然后跳过写入您不需要的行,或者是一个逐行查看的流,然后记下最后一行结束的位置。。然后找到下一个相关数据的位置并覆盖该数据块。有这个文件的(小)示例吗?你的解释不太清楚。您能否向我们显示文件的一小部分、可能的输入和预期结果?此
单个.Substring(0,lineWithStar.Length)
不会更改整个from查询。如果希望获得完整的答案,则需要再指定一点。请使用一些并发集合来this@arekzyla,你完全正确,谢谢。我只是快速地从原始代码中复制了一些部分,专注于性能,却忽略了这一点。需要删除并行或使用并发收集。感谢快速响应,结果应该如下所示:700204*7002051006143305*700205100662305*7002051006623904 7002051000667271*700205120015472*来源是:700204*70020510061436*7002041232323234332 700205100662305*7002051001413623327002051006623443904 700205100667271*700205120015472*@LukaszStanulewicz,我已经更新了我的回复。您在该文件中有多少图案线,以及规则线和图案线之间的比例是多少?您应该用这些信息编辑问题。这不是答案欢迎来到StackOverflow。请使用下面的帖子添加此信息