使用正则表达式将字符串转换为字典(需要优化)

本文关键字:优化 字典 正则表达式 字符串 转换 | 更新日期: 2023-09-27 17:50:16

我有一个格式为"$0Option one$1$Option two$2$Option three"(等)的字符串,我想将其转换为一个字典,其中每个数字对应一个选项。对于这个问题,我目前有一个可行的解决方案,但是由于这个方法对我导入的每个条目(几千个)都被调用,我希望它尽可能地优化。

public Dictionary<string, int> GetSelValsDictBySelValsString(string selectableValuesString)
{
    // Get all numbers in the string. 
    var correspondingNumbersArray = Regex.Split(selectableValuesString, @"[^'d]+").Where(x => (!String.IsNullOrWhiteSpace(x))).ToArray();
    List<int> correspondingNumbers = new List<int>();
    int number;
    foreach (string s in correspondingNumbersArray)
    {
        Int32.TryParse(s, out number);
        correspondingNumbers.Add(number);
    }
    selectableValuesString = selectableValuesString.Replace("$", "");
    var selectableStringValuesArray = Regex.Split(selectableValuesString, @"['d]+").Where(x => (!String.IsNullOrWhiteSpace(x))).ToArray();
    var selectableValues = new Dictionary<string, int>();
    for (int i = 0; i < selectableStringValuesArray.Count(); i++)
    {
        selectableValues.Add(selectableStringValuesArray.ElementAt(i), correspondingNumbers.ElementAt(i));
    }
    return selectableValues;
}

使用正则表达式将字符串转换为字典(需要优化)

在你的代码中引起我注意的第一件事是它处理输入字符串三次:两次使用Split(),一次使用Replace()。对于这项工作,Matches()方法是比Split()更好的工具。有了它,您可以一次提取所需的所有内容。它也使代码更容易阅读。

我注意到的第二件事是所有那些循环和中间对象。你已经在使用LINQ了;真的使用它,你可以消除所有的混乱提高性能。查看一下:

public static Dictionary<int, string> GetSelectValuesDictionary(string inputString)
{
  return Regex.Matches(inputString, @"(?<key>[0-9]+)'$*(?<value>[^$]+)")
    .Cast<Match>()
    .ToDictionary(
        m => int.Parse(m.Groups["key"].Value),
        m => m.Groups["value"].Value);
}

指出:

  • Cast<Match>()是必要的,因为MatchCollection只宣传自己是IEnumerable,我们需要它是IEnumerable<Match>
  • 我使用[0-9]而不是'd,因为您的值可能包含来自非拉丁书写系统的数字;在。net中,'d匹配它们。静态Regex方法,如Matches()自动缓存Regex对象,但如果这个方法将被调用很多(特别是如果你正在使用很多其他Regex,太),你可能想要创建一个静态Regex对象。如果性能真的很关键,你可以指定Compiled选项,当你在它。
  • 我的代码,像你的一样,没有尝试处理格式错误的输入。特别是,如果数字太大,我的将抛出异常,而您的只是将其转换为零。这可能与您的实际代码无关,但是看到您调用TryParse()而不检查返回值,我感到不得不表达我的不安。:/
  • 你也没有确保你的钥匙是唯一的。像@Gabe一样,我使用数字值作为键,因为它们是唯一的,而字符串值不是。我相信这对你的真实数据来说也不是问题。)

您的selectableStringValuesArray实际上不是一个数组!这意味着每次索引它(使用ElementAt或使用Count计数)时,它都必须重新运行regex并遍历结果列表以查找非空白。你需要这样做:

var selectableStringValuesArray = Regex.Split(selectableValuesString, @"['d]+").Where(x => (!String.IsNullOrWhiteSpace(x))).ToArray();

你也应该修复你的correspondingNumbersString,因为它有同样的问题。

我看到你正在使用c# 4,虽然,所以你可以使用Zip来组合列表,然后你就不必创建一个数组或使用任何循环。您可以这样创建字典:

return correspondingNumbersString.Zip(selectableStringValuesArray,
       (number, str) => new KeyValuePair<int, string>(int.Parse(number), str))
      .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);