如何更换字符?很快

时间:2017-04-14 18:30:09

标签: c#-4.0

我有这个foreach循环以正确的顺序替换字符串中的字符,但它会慢...

输入字符串可以有不同的长度.. 字符串长度范围1000 - 1000000

每个char查找只需要1.2毫秒..

但是输入字符串会降低速度,无论如何要更快地替换字符..

charlist只是char替换..

我正在使用charlist项目中的input替换value2字符串中的字符..

List<CharItem> charlist; //Charlist count = 98..

var txxt = input.ToCharArray();
string test = "";

foreach (var itm in txxt)
{
   var itm2 = (from x in charlist where x.Value == itm select x).FirstOrDefault();
   if (itm2 != null)
     test = test + itm2.Value2;
}



public class CharItem
{
    public char Value { get; set; }
    public char Value2 { get; set; }

    public override string ToString()
    {
        return "1." + Value + "| 2." + Value2;
    }
}

至于这句话test = test + itm2.Value2;我不认为字符串构建者更快......

无论如何要加快速度,但是char命令需要相同,只需更换.. 我知道我的硬件速度有限,只是优化我的代码..

2 个答案:

答案 0 :(得分:1)

这里有两个问题:

  • 在每个for循环步骤中重新创建字符串对象。您可以使用 StringBuilder或IEnumerable,
  • 在charlist中搜索有O(N)时间 复杂性,但如果替换List,则可以在O(logN)时间内完成 与...字典。

所以我建议使用此代码:

List<CharItem> charlist; //Charlist count = 98..  
var replacementRule = charlist.ToDictionary(item => item.Value, item => item.Value2);

char tempC;
return new string(input
        .Select(c => replacementRule.TryGetValue(c, out tempC) ? tempC : (char?) null)
        .Where(c => c != null)
        .Select(c => (char)c)
        .ToArray()
    );

第二种方式是:

var sb = new StringBuilder();;
foreach (var c in input)
{
    char tempC;
    if (replacementRule.TryGetValue(c, out tempC))
    {
        sb.Append(tempC);
    }
}
return sb.ToString();

这里是并行LINQ简单并行化的第三个:

const int batchCount = 8; // ~ logical processor count
var batchSize = (input.Length - 1) / batchCount + 1);

    var result = Enumerable
    .Range(0, batchCount)
    .Select(
        ind => new
        {
            Index = ind,
            StringPart = input.Substring(
                Math.Min(input.Length, batchSize * ind), 
                Math.Min(batchSize, input.Length - Math.Min(input.Length, batchSize * ind))
            )
        })
    .AsParallel()
    .Select(
        batch => new
        {
            batch.Index,
            Result = ReplaceInBatch(replacementRule, batch.StringPart)
        })
    .OrderBy(batch => batch.Index)
    .Aggregate(new StringBuilder(input.Length), (sb, batch) => sb.Append(batch.Result))
    .ToString();

// ....
// somewhere
private static StringBuilder ReplaceInBatch(IReadOnlyDictionary<char, char> replacementRule, string batch)
{
    var sb = new StringBuilder();
    foreach (var c in batch)
    {
        char tempC;
        if (replacementRule.TryGetValue(c, out tempC))
        {
            sb.Append(tempC);
        }
    }
    return sb;
}

完整的测试控制台应用。它用小写字母替换小写字母:link
两种方式都有两个版本 - 差异可以在这里找到:link
并行方式的第三次修订。

答案 1 :(得分:0)

您可以尝试以下操作:

var charlist = Enumerable.Range(50, 10)
    .Select(x => new CharItem { Value = (char)x, Value2 = (char)(x + 1) }).ToList();
// charlist = { [1.2| 2.3], [1.3| 2.4], ... [1.9| 2.:], [1.:| 2.;], [1.;| 2.<] }
var dict = charlist.ToDictionary(x => x.Value, x => x.Value2);
new string("12345".Select(x => dict.ContainsKey(x) ? dict[x] : x).ToArray())
// "13456"