2017-04-14 26 views
1

我有了這個foreach循環替換以正確的順序串一個字符,但它是慢..如何取代chars inorder?快速

輸入字符串可以有不同的長度.. 字符串長度範圍1000 - 百萬

每個CHAR擡頭只需要1.2毫秒..

但它減緩下來,反正快更換字符輸入字符串..

的charlist只是字符替換..

我更換的input字符串與value2從charlist項目字符..

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;我不認爲一個StringBuilder是任何更快..

反正加快這,但焦炭訂單需要是相同的,只是更換.. 我知道我的硬件速度是有限的,只是我的優化代碼..

+0

不要連接+,而是使用StringBuilder代替 –

+1

那麼你可以先在循環中不使用字符串連接...使用'StringBuilder'而不是'char []'來轉換爲'字符串'在結尾。但是,不清楚你的代碼是否正確*。你真的打算徹底刪除任何不屬於'charlist'的字符嗎? 'charlist'有多大?你可以發佈[mcve]嗎?現在有多慢? –

+0

這是一個文本加密算法,所以我需要替換每個字符.. linq表達式是查找正確的字符並將其替換。 – ArchAngel

回答

1

兩個問題在這裏:

  • 您重新在每個for循環一步字符串對象。您可以使用StringBuilder的 或IEnumerable的,在charlist
  • 搜索有O(n)的時間複雜度 ,但你可以做到這一點在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
並行方式有第三次修訂。

+0

我沒有更換charlist值,我正在替換輸入字符串字符.. – ArchAngel

+0

so?這是我在這裏做的。 'charlist'定義替換規則。然後,我將它們應用於輸入 – pkuderov

+0

'TryGetValue'無法處理'null',因此您的代碼無效。 – ArchAngel

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" 
+0

我不明白這是如何解決的,因爲我的代碼是以字符數組的形式讀取'input',並遍歷每個字符並替換它們。但是它們必須處於相同訂單.. – ArchAngel