【问题标题】:I need to extract string(that is coming from a list) from line我需要从行中提取字符串(来自列表)
【发布时间】:2018-01-31 16:46:01
【问题描述】:

我正在尝试提取作为列表项的“字符串”。有 200 行我需要从中提取作为列表项的字符串,所述列表中有 54474 个项,我正在传递要从中提取列表项作为子字符串的行存在。我将两者都作为参数传递给函数,如下所示:-

private static string FindMatchingSkill(string line, List<string> skillsfromMongoDB)
    {
        StringBuilder builtString = new StringBuilder();
        foreach (var item in skillsfromMongoDB)
        {
                string temp = " " + item;
                builtString.Append(line.Substring(line.IndexOf(temp), temp.Length).Trim() + ", ");
        }
        return builtString.ToString();
    }

【问题讨论】:

  • 如果求职者的简历是这样被过滤的,我为他们感到抱歉。 ;)
  • 能否请您阅读How to Ask,然后阅读minimal reproducible example?您应该已经向我们提供了示例输入数据(作为有效的 C# 代码)、工作代码和所需的输出。目前你的输入看起来不完整,你的代码没有编译,而且它似乎没有输出你要求的东西(但我不能说清楚,因为解释不清楚)。
  • 不要使用异常来控制流量。一开始就很慢。计算索引,然后使用if 语句决定是否使用它。

标签: c# performance linq


【解决方案1】:

您要做的第一件事是不要对原始字符串进行子串化,而是从列表中打印出项目。
而不是:

Console.WriteLine(line.Substring(line.IndexOf(item), item.Length).Trim() + ", ");

使用

Console.Write(item +", ");

但要做到这一点,您只需要获取实际在字符串中的项目,因此您的循环应该是这样的:

foreach (var item in data.Where(i => line.IndexOf(i) > -1)

这可能会给您留下一些误报,因为如果该行包含javascript 而不是java,您将得到两者。

所以下一步是确定什么是完整的世界,什么不是 - 现在这可能是个问题,因为 dot net 是两个词,但它只是一个项目。此外,原始字符串中的项目可能后跟除空格以外的字符 - 例如逗号、点、分号等。
因此,您不仅需要使用IndexOf,还需要确保您找到的项目不是更大项目的一部分 - 而且由于您的列表项目不限于单个单词,这确实带来了困难。

我可能会建议这样的事情:

foreach (var item in data.Where(i => line.IndexOf(i) > -1 && !Char.IsLetter(line[line.IndexOf(i) + i.Length + 1])  && !Char.IsLetter(line[line.IndexOf(i) - 1]))
{
    Console.Write(item +", ");
}

测试项目后的字符以确保它不是字母。如果是,那么它是一个误报。请注意,由于您的项目可能包含非字母字符,您可能仍然会得到误报 - 如果您在列表中同时拥有 dot net coredot net,但该行只有 dot net core,您将得到 @ 的误报987654332@。但是,这是一个边缘情况,我认为可以忽略它。

【讨论】:

  • Tx @zohar peled plz 看看函数它可能让我对理解私有字符串 FindMatchingSkill(string line, List SkillsfromMongoDB) { StringBuilder builtString = new StringBuilder(); 有更多想法foreach(来自MongoDB的技能中的变量项){尝试{字符串临时=“”+项目; builtString.Append(line.Substring(line.IndexOf(temp), temp.Length).Trim() + ", "); } catch (Exception ee) { if (ee.Message.Contains("StartIndex 不能小于零。")) continue; } return builtString.ToString(); }
  • 请避免将代码粘贴到 cmets 中。相反,请使用您要询问的代码编辑您的问题。
  • 使用正则表达式匹配单词边界可能会更好。 (我的第一个直觉是匹配一个正则表达式,但是有 50k 个项目我想这会有点混乱......)
  • 请注意,某些技能可能是以数字结尾的编程语言或软件包的名称,因此可能不建议使用IsLetter。此外,这不会检查前边界。
  • @Nyerguds 正确。我想使用正则表达式,但我认为开销太大
【解决方案2】:

这是一个例子:

var result = new Dictionary<string, string[]>();
var searchInLines = new string[200]; // filled with resumes 
var dictionary = new string[50000]; // search dictionary

searchInLines.AsParallel()
    .WithDegreeOfParallelism(Environment.ProcessorCount * 2)
    .Select(searchInLine =>
        {
            result.Add(searchInLine, dictionary.Where(s => searchInLine.Contains(s)).ToArray());
            return string.Empty;
        })
    .ToList();

生成带有“恢复”的字典以找到字典项目。

如果你使用不准确的string.Contains,那么它会在0.2秒内快速生效

如果你使用像Regex.IsMatch(searchInLine, $"\\b{s}\\b")) 这样的正则表达式(查找单词),那么它会在 30 秒内缓慢工作。

选择是你的

【讨论】:

  • string.Contains 可能会产生误报,正如我在回答中所解释的那样。也许一个好的方法是使用 string.Contains 尽可能快地获得可能的匹配项,然后进一步过滤它们以最大限度地减少误报。
  • @ZoharPeled 这是下一步的 OP 选择
【解决方案3】:

data 的列表变大了不好循环。我建议循环通过这条线,因为它更小。考虑到单词之间总是有空格。

List<string> data = new List<string>() { "Delphi", "dot net", "java", "Oracle" }
String line = "Dheeraj has experience in dot net java programming Oracle javascript and Delphi";

foreach (var item in line.Split(new char[] { ' ' }))
{
    // If you use Contains here, it will use sorting and searching the keyword
    if(data.Contains(item))
    {
        Console.WriteLine(item);
    }
}

【讨论】:

  • 这个代码永远找不到"dot net"。 OP想要什么也有点不清楚-您的代码与他们的代码不同。我怀疑两者都不对。
  • @praty 我已经在 Zohar Peled 先生的回复下方发布了整个函数的代码,问题是如果这样做,那么我将不得不用“S++”或“”拆分我的字符串,但这样做这完全改变了输出,因为列表中有我的列表中的项目为“C# DotNet”和“C#”“Dot Net”,所以如果我拆分我的字符串,那么它将完全改变输出,这将没有用作为我之前按照你的建议试过了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多