我有一个很长的字符串,以及索引和值的排序字典。我应该检查字典中的元素并将值插入字符串中的指定索引。我写了下面的代码,它工作得很好但很慢:
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秒钟。
是否有更有效的方法来编写此方法?
谢谢,
玛雅
答案 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();
}
它只使用附加功能,与原始代码相同