2011-08-28 107 views
3

我有一个字符串,这是一个很长的字符串和索引和值。我应该查看字典中的元素并将该值插入字符串中的指定索引。我写了下面的代码,它工作得很好,但速度很慢:C#:插入字符串到另一个字符串 - 性能问题

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

词典可能是非常大的,并且包含500000元。 我觉得这个函数慢的是Insert()方法。对于100,000个元素的字典,花了将近5秒。

有没有更有效的方法来写这种方法?

感谢,

玛雅

+0

请告诉我该数据源使用追加? –

+0

如果它将'_tags'添加到一个词典中,那么'text'中的内容是什么? – MPelletier

回答

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

它只有在beeing与您的原代码

2

更好的方式是排序为插入的项目,然后添加他们一个接一个。

既然你没有评论重叠,也许你有你的物品排在第一位?

+1

这可能会更快,但我不认为有任何保证。简单的配置文件可以找到任何方法。 –

+0

它肯定会更快,因为StringBuilder被设计用于追加,并且每个插入必须进一步向下移动内存块。 –

+0

是的,但排序并不快...... –

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

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

+0

请考虑在他的示例StringBuilder中已经创建了一些字符串。该字符串可能很长。 “新的StringBuilder(文本)”。 – Tigran

+0

噢,是的,如果长度大于StringBuilder的容量,它会慢一点。但你可以自己重置容量:) – shenhengbin

+0

我的意思是,在大字符串的情况下,从性能的角度来看,Insert会受到这个影响。 – Tigran

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参数最初用于初始化StringBuilder

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

我们可以通过将原始文本转换为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(); 
} 

注 - 我对你们的上下文假设整个堆,所以这可能不是你完全正确工作。特别要注意的是,.Union()会丢弃重复项目,尽管这有一些简单的解决方法。

+0

但这里(文本)参数在哪里? – Tigran

+0

@Tigran - 感谢您的注意,我已经更新了我的答案。 – Bevan