2013-08-21 21 views
0

如何以最短和有效的方式將各種字符串加入字符串。目前我正在做以下幾種方式c#以較短和有效的方式加入字符串

string str1 = string.Format(BitConverter 
     .ToString(pass_packet, local_index + 511, 1) + 
     BitConverter.ToString(pass_packet, local_index + 510, 1) + 
     BitConverter.ToString(pass_packet, local_index + 509, 1) + 
     BitConverter.ToString(pass_packet, local_index + 508, 1) + 
     ... + BitConverter.ToString(pass_packet, local_index + 400, 1)); 
+1

使用StringBuilder效率.. – Naren

+0

可能重複的[我應該如何連接字符串?](http://stackoverflow.com/questions/3102806/how-should-i-concatenate-strings) – wudzik

+1

什麼是'pass_packet' ,你究竟想要做什麼?它看起來像你有效地試圖獲得負載的字節*以相反的順序*,表示爲十六進制...這是一個相當不尋常的要求。那絕對是你想要做的? –

回答

5

我不認爲你需要在所有Concat的 - 定的測試數據。以字節數組爲單位,反轉它們,然後通過一個BitConverter.ToString調用!

class Program 
{ 
    static int ITERATIONS = 100000; 
    static void Main(string[] args) 
    { 
     var pass_packet = Enumerable.Range(0, 1024).Select(i => (byte)i).ToArray(); 

     int local_index = 5; 

     var sw = Stopwatch.StartNew(); 
     var result = StringBuilderTEST(pass_packet, local_index); 

     Console.WriteLine(result + " in {0}ms", sw.ElapsedMilliseconds); 

     //second option 
     sw.Restart(); 
     var result2 = ArrayReversalTEST(pass_packet, local_index); 
     Console.WriteLine(result2 + " in {0}ms", sw.ElapsedMilliseconds); 

     sw.Restart(); 
     var result3 = ArrayReversal2TEST(pass_packet, local_index); 
     Console.WriteLine(result3 + " in {0}ms", sw.ElapsedMilliseconds); 

     sw.Restart(); 
     var result4 = StupidlyFastTEST(pass_packet, local_index); 
     Console.WriteLine(result4 + " in {0}ms", sw.ElapsedMilliseconds); 

     Console.WriteLine("Results are equal? " + (result == result2 && result == result3 && result == result4)); 
     Console.ReadLine(); 
    } 

    private static string StringBuilderTEST(byte[] pass_packet, int local_index) 
    { 
     string result = null; 
     for (int b = 0; b < ITERATIONS; b++) 
     { 
      var sb = new StringBuilder(); 
      for (int i = 511; i >= 400; i--) 
       sb.Append(BitConverter.ToString(pass_packet, local_index + i, 1)); 
      result = sb.ToString(); 
     } 
     return result; 
    } 

    private static string ArrayReversalTEST(byte[] pass_packet, int local_index) 
    { 
     string result = null; 
     for (int b = 0; b < ITERATIONS; b++) 
     { 
      var selectedData = pass_packet.Skip(400 + local_index).Take(112).Reverse().ToArray(); 
      result = BitConverter.ToString(selectedData).Replace("-", ""); 
     } 
     return result; 
    } 

    private static string ArrayReversal2TEST(byte[] pass_packet, int local_index) 
    { 
     string result = null; 
     for (int b = 0; b < ITERATIONS; b++) 
     { 
      var tempArray = new byte[112]; 
      Array.Copy(pass_packet, 400 + local_index, tempArray, 0, 112); 
      Array.Reverse(tempArray); 
      result = BitConverter.ToString(tempArray).Replace("-", ""); 
     } 
     return result; 
    } 

    private static string StupidlyFastTEST(byte[] pass_packet, int local_index) 
    { 
     string result = null; 
     string hex = "ABCDEF"; 
     for (int it = 0; it < ITERATIONS; it++) 
     { 
      var tempArray = new char[112 * 2]; 
      int tempArrayIndex = 0; 
      for (int i = 511; i >= 400; i--) 
      { 
       var b = pass_packet[local_index + i]; 
       tempArray[tempArrayIndex++] = hex[b >> 4]; 
       tempArray[tempArrayIndex++] = hex[b & 0x0F]; 
      } 
      result = new string(tempArray); 
     } 
     return result; 
    } 
} 

結果:

Test 1 in 478ms 
Test 2 in 1134ms 
Test 3 in 516ms 
Test 4 in 114ms 
Results are equal? True 

正如你可以重寫代碼中看到我的頭兩個嘗試不是很有效 - 尤其是考慮創建和維護所需要的額外的時間。然而,一些快速測試顯示,這是由於String.Replace需要使結果相同 - 因爲默認轉換器在數組中的每個字節對之間放置了' - ',原始算法由於單字節長度而沒有看到。

//Without String.Replace in tests 2 and 3 
Test 1 in 475ms 
Test 2 in 704ms 
Test 3 in 92ms 
Test 4 in 115ms 
Results are equal? False 

正如你可以在原始性能方面看Test3的是最快的 - 雖然默認的輸出包含「 - 」每一個字節之間。

Test4用快速手動版本取代了轉換器 - 省去了字節分隔符 - 並且是原始結果中速度最快的。我懷疑高速緩存臨時數組,並用一個更大的256元素十六進制數組替換 分部&模數學公式 *將顯着提高速度,但考慮到這一點證明將停止在這裏。

*編輯,用位操作代替分割和模數以顯着加速。

+0

請問-1請評論?根本不需要加入字符串的解決方案總是比加入字符串更快。高級別的優化。 – NPSF3000

+0

我同意你的意見,但是隻是發佈代碼,不要發表回覆說你會發布代碼..多數民衆贊成在一個評論。 – CaveCoder

+0

@ Xikinho90回答完全可以接受,稍後再添加細節! –

0

string.Concat是你的朋友。

string.Concat(BitConverter.ToString(pass_packet, local_index + 511, 1), 
       BitConverter.ToString(pass_packet, local_index + 510, 1), 
       BitConverter.ToString(pass_packet, local_index + 509, 1), 
       BitConverter.ToString(pass_packet, local_index + 508, 1),     
       BitConverter.ToString(pass_packet, local_index + 400, 1)); 

有兩個有趣的重載:string.Concat(params Object[] args)string.Concat(params string[] values)。兩者都接受可變長度的參數(正如我所做的那樣)或者正確類型的數組。甚至有超載接受IEnumerable<string>IEnumerable<T>,其中T是任何一種類型。

+1

我認爲C#編譯器已經使用「+」運算符將多個連接轉換爲「string.Concat()」的單個調用。我嘗試了這一點,並使用Reflector檢查了結果,並且在推入所有參數後僅調用了「string.Concat()」一次。 –

+0

@MthetheWWatson是的,看ILSpy中的IL代碼,我可以看到它......它似乎稱'string.Concat'可能更好的重載:-) – xanatos

0

這有點棘手,但我認爲這完成了工作。

string myString = new String(Enumerable.Range(400,111).SelectMany(x => BitConverter.ToString(pass_packet, x + 509, 1)).ToArray()); 
+1

'Enumerable.Range(511,400)'將數字從511到910這是不正確的。 –

+0

固定,謝謝.. – CaveCoder

2

我會做這樣的:

StringBuilder sb = new StringBuilder(); 

for (int i = 511; i >= 400; --i) 
    sb.Append(BitConverter.ToString(pass_packet, local_index + i, 1)); 

string str1 = sb.ToString(); 
+0

感謝您的解決方案 – prattom

相關問題