【问题标题】:Increasing speed of matching strings in list提高列表中匹配字符串的速度
【发布时间】:2018-09-29 16:45:57
【问题描述】:

我有 >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

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

【问题讨论】:

  • 您是如何阅读文件的?我猜它读到记忆?所以你也在内存中制作第二份副本?您最好读入行并写出新文件以替换它,并跳过写入您不想要的文件,或者逐行查看的流,然后记下最后一个 OK 行结束的位置。 . 然后找到下一个相关数据的位置并覆盖该块。
  • 有文件的(小)示例吗?
  • 你的解释不是很清楚。您能否向我们展示文件的一小部分、可能的输入和预期结果?
  • 这个single.Substring(0, lineWithStar.Length) 不会改变整个查询。如果您想要有帮助的答案,您需要指定更多。

标签: c# lambda matching


【解决方案1】:

您有嵌套循环,这会影响您的性能。此外,您还做了很多额外的字符串和列表分配。

我会这样做:浏览文件一次以找到您需要删除的所有模式。然后再重复一次,并为每一行立即决定是否需要删除该行或保留它。然后,您可以创建包含需要保留的行的新列表,也可以直接写入新文件,或者只添加要在单独集合中删除的项目。类似的东西

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);
});

更新:您可能不需要 Parallel.Foreach 并且简单的 for 循环可以运行得足够快。但是如果你需要并行,你应该考虑线程安全的结果集合。

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

【讨论】:

  • 为此使用一些并发集合
  • @arekzyla,你是绝对正确的,谢谢。我只是快速地从原始代码中复制了部分内容,专注于性能而错过了这一点。要么需要移除并行,要么使用并发收集。
  • 感谢快速响应的结果应该是这样的:700204 * 700205100614136 * 700205100662305 * 7002051006623443904 700205100667271 * 700205120015472 *来源是:700204 * 700205100614136 * 7002041232323234332 700205100662305 * 7002051006141362332 7002051006623443904 700205100667271 * 700205120015472 * 跨度>
  • @LukaszStanulewicz,我已经更新了我的回复。你在那个文件中有多少条图案线,常规线和图案线的比例是多少?
【解决方案2】:

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

123*

123456

1245

【讨论】:

  • 您应该使用此信息编辑问题。这不是答案
  • 欢迎来到 StackOverflow。请使用您帖子下方的edit button 添加此信息
猜你喜欢
  • 2011-12-30
  • 2012-07-24
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2021-10-10
  • 2023-03-28
  • 2022-01-11
  • 1970-01-01
相关资源
最近更新 更多