假设我有一个像这样声明的字符串数组:
String[] strings = new String[ 1024 ];
给出一系列像这样声明的键值对:
KeyValuePair<String, String>[] pairs = new KeyValuePair<String, String>[ 50 ];
解决方案有哪些可行的解决方法:
for ( int i = 0; i < 1024; ++i )
{
foreach ( var kv in pairs )
{
strings[ i ] = strings[ i ].Replace( kv.Key, kv.Value );
}
}
此代码只是任意的,只是为了显示实际问题。给定了许多在编译时已知的键值,如何进行高效的String.Replace,并可能减少方法调用并复制String(每次调用String.Replace都会产生一个新的不可变String,而不是当有很多替换呼叫时非常有效率?)
答案 0 :(得分:2)
我会说将字符串转储到List中,然后每个stringbuilders执行replace调用。这将节省额外的不可变字符串对象的创建。如果你只需要少量的替换品,那么很可能会有一点开销,但是既然你已经说过会有很多替换,那么这应该会有所帮助。
答案 1 :(得分:2)
它对循环次数没有帮助,但是如果你使用StringBuilder作为中间件,它会使用相同的参数签名集进行.Replace调用。
编辑:
不确定它是否更快,但您可以将Regex.Replace与评估者委托一起使用。
如果您使用密钥构建搜索正则表达式: (KEY1 | KEY2 | KEY3 | KEY4 ...)
然后将委托传递给.Replace,您可以根据Match的Value属性返回查找。
public string ReplaceData(Match m)
{
return pairs[m.Value];
}
...
pairs.Add("foo","bar");
pairs.Add("homer","simpson");
Regex r = new Regex("(?>foo|homer)");
MatchEvaluator myEval = new MatchEvaluator(class.ReplaceData);
string sOutput = r.Replace(sInput, myEval);
答案 2 :(得分:1)
您可以使用收到的建议(例如使用StringBuilder)和并行扩展,使用您的计算机中有多少核心来并行完成工作。
看看这段代码:
class Program {
static void Main(String[] args) {
// Filling the data
List<KeyValuePair<String, String>> map = new List<KeyValuePair<String, String>>();
List<StringBuilder> strings = new List<StringBuilder>();
List<StringBuilder> strings2 = new List<StringBuilder>();
for (Int32 i = 0; i < 50; i++) {
String key = String.Format("[KEY{0}]", i);
String value = String.Format("Text of KEY{0}", i);
KeyValuePair<String, String> keyValuePair = new KeyValuePair<String, String>(key, value);
map.Add(keyValuePair);
}
for (Int32 i = 0; i < 1024; i++) {
StringBuilder text = new StringBuilder();
foreach (KeyValuePair<String, String> keyValuePair in map) {
text.AppendFormat("Some text before - {0} - Some text after.", keyValuePair.Key);
text.AppendLine();
}
strings.Add(text);
strings2.Add(text);
}
// Measuring the normal loop
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
foreach (StringBuilder text in strings) {
foreach (KeyValuePair<String, String> eachMap in map) {
text.Replace(eachMap.Key, eachMap.Value);
}
}
stopwatch.Stop();
Console.WriteLine("Time with normal loop: {0}", stopwatch.Elapsed);
// Measuring the parallel loop
stopwatch.Reset();
stopwatch.Start();
Parallel.ForEach(strings2, text => {
foreach (KeyValuePair<String, String> eachMap in map) {
text.Replace(eachMap.Key, eachMap.Value);
}
});
stopwatch.Stop();
Console.WriteLine("Time with parallel: {0}", stopwatch.Elapsed);
Console.ReadLine();
}
}
看看我的nootebook(AMD Turion64 X2 - 2内核)上运行的一些措施:
正常循环的时间:00:00:03.5956428
并行时间:00:00:01.8707367
正常循环的时间:00:00:02.1467821
平行时间:00:00:01.4627365
正常循环的时间:00:00:03.4123084
并行时间:00:00:01.6704408
希望这有帮助。
Ricardo Lacerda Castelo Branco
答案 3 :(得分:0)
这应该通过选择值
来减少字符串操作 String[] strings = new String[1024];
KeyValuePair<String, String>[] pairs = new KeyValuePair<String, String>[ 50 ];
String[] replaced = strings.Select(x =>
pairs.Any( y => y.Key == x ) ?
pairs.Where( z => z.Key == x).Select( val => val.Value).First() : x )
.ToArray();
答案 4 :(得分:0)
我认为Joe和Agent_9191的建议基本相同:
const int NUM_STRINGS = 1024;
string[] strings = new string[NUM_STRINGS];
StringBuilder[] stringBuilders = new StringBuilder[NUM_STRINGS];
// ensure that all StringBuilder objects are initialized
for (int i = 0; i < NUM_STRINGS; i++) {
stringBuilders[i] = new StringBuilder(strings[i]);
}
KeyValuePair<string, string>[] pairs = new KeyValuePair<string, string>[50];
for (int i = 0; i < NUM_STRINGS; i++) {
foreach (var kv in pairs) {
// StringBuilder is mutable;
// this actually modifies the instance
stringBuilders[i].Replace(kv.Key, kv.Value);
}
strings[i] = stringBuilders[i].ToString();
}