c#:插入字符串是另一个性能问题
本文关键字:另一个 性能 问题 字符串 插入 | 更新日期: 2023-09-27 18:06:55
我有一个字符串,它很长,还有一个索引和值的排序字典。我应该遍历字典中的元素并将值插入到字符串中指定的索引中。我编写了以下代码,运行良好,但非常慢:
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秒。
是否有更有效的方法来编写这个方法?
谢谢,玛雅
更好的方法是对要插入的项进行排序,然后一个接一个地添加它们。
既然你没有评论重叠,也许你一开始就把你的项目排序了?
您的原始代码将根据从_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));
我错过了最初用于初始化StringBuilder
的text
参数。
为了避免在内存中打乱文本(由StringBuilder.Insert()
引起),我们希望坚持使用StringBuilder.Append()
。
我们可以将原始文本转换为另一个KeyValuePair
实例序列,将它们与原始列表合并并按顺序处理。
它看起来像这样(注意: adhoc code):
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()
将丢弃重复项,尽管有简单的解决方法。
如果你设置了索引,那么插入不会改变其他索引,但是当你的代码说"是"时,我也会假设这样做。
你能测试一下这个吗?
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();
}
它只在与原始代码相同的情况下使用append
我不知道你的数据怎么样。
但是在我的测试中,它运行得很快(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();
如果你可以使用append()而不是insert(),它只需要35ms…