C#:将字符串插入另一个字符串 - 性能问题

时间:2011-08-28 08:19:38

标签: c# string performance stringbuilder

我有一个很长的字符串,以及索引和值的排序字典。我应该检查字典中的元素并将值插入字符串中的指定索引。我写了下面的代码,它工作得很好但很慢:

private string restoreText(string text){
  StringBuilder sb = new StringBuilder(text);
  foreach(KeyValuePair<int, string> pair in _tags){
    sb.Insert(pair.Key, pair.Value);
  }
  return sb.ToString();
}

字典可能非常大,包含500,000个元素。 我认为使这个函数变慢的原因是Insert()方法。对于100,000个元素的字典,花了将近5秒钟。

是否有更有效的方法来编写此方法?

谢谢,

玛雅

4 个答案:

答案 0 :(得分:2)

更好的方法是对要插入的项目进行排序,然后逐个添加它们。

由于您没有对重叠进行评论,或许您首先对项目进行了排序?

答案 1 :(得分:2)

您的原始代码将根据从_tags返回的项目的顺序给出不同的结果;我非常怀疑这不是你的意图。

相反,按顺序对标记进行排序,然后按正确的顺序将它们添加到字符串构建器中:

private string restoreText(string text)
{
    StringBuilder sb = new StringBuilder();
    foreach( KeyValuePair<int, string> pair in _tags.OrderBy(t => t.Key))
    {
        sb.Append(pair.Value);
    }

    return sb.ToString();
}

如果您真的希望尽可能快地完成此操作,请事先初步确定StringBuilder的容量:

    StringBuilder sb = new StringBuilder(_tags.Sum(k => k.Value.Length));

<强>更新

我错过了最初用于初始化text的{​​{1}}参数。

为了避免在内存中混乱文本(由StringBuilder引起),我们希望坚持使用StringBuilder.Insert()

我们可以通过将原始文本转换为另一个StringBuilder.Append()实例序列,将其与原始列表合并并按顺序处理来实现。

它看起来像这样(注意:adhoc代码):

KeyValuePair

注意 - 我已经对你的背景做了一大堆假设,所以这可能不适合你。特别要注意的是,private string restoreText(string text) { var textPairs = text.Select( (c,i) => new KeyValuePair<int,string>(i, (string)c)); var fullSequence = textPairs.Union(_tags).OrderBy(t => t.Key); StringBuilder sb = new StringBuilder(); foreach( KeyValuePair<int, string> pair in fullSequence) { sb.Append(pair.Value); } return sb.ToString(); } 会丢弃重复项,但有一些简单的解决方法。

答案 2 :(得分:1)

我不知道你的数据怎么样。

但在我的测试中,它运行得很快(564ms)。

        Dictionary<int, string> _tags = new Dictionary<int, string>();
        for (int i = 0; i < 1000000; i++)
        {
            _tags.Add(i, i.ToString().Length + "");
        }

        string text = new String('a' , 50000000);
        Console.WriteLine("****************************************");

        System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();

        StringBuilder sb = new StringBuilder(text);
        foreach (KeyValuePair<int, string> pair in _tags)
        {
            sb.Insert(pair.Key, pair.Value);
        }

        sw.Stop();

        Console.WriteLine("sw:" + sw.ElapsedMilliseconds);
        Console.ReadKey();

如果你可以使用追加()而不是插入(),它只需要35毫秒......

答案 3 :(得分:1)

如果您设置了索引以便插入不会更改其他插入,但是当您的代码显示“是”时,我不会得到的内容我也会这样认为。

你能测试一下这个:

private string RestoreText(string text)
{
    var sb = new StringBuilder();
    var totalLen = 0;
    var orgIndex = 0;
    foreach (var pair in _tags.OrderBy(t => t.Key))
    {
        var toAdd = text.Substring(orgIndex, pair.Key - totalLen);
        sb.Append(toAdd);
        orgIndex += toAdd.Length;
        totalLen += toAdd.Length;

        sb.Append(pair.Value);
        totalLen += pair.Value.Length;
    }
    if (orgIndex < text.Length) sb.Append(text.Substring(orgIndex));
    return sb.ToString();
}

它只使用附加功能,与原始代码相同