簡體   English   中英

如何將字符串拆分為有效的方式C#

[英]How to split a string into efficient way c#

我有一個像這樣的字符串:

 -82.9494547,36.2913021,0
 -83.0784938,36.2347521,0
 -82.9537782,36.079235,0

我需要這樣的輸出:

 -82.9494547 36.2913021, -83.0784938 36.2347521, -82.9537782,36.079235

我已經嘗試過以下代碼來實現所需的輸出:

string[] coordinatesVal = coordinateTxt.Trim().Split(new string[] { ",0" }, StringSplitOptions.None);

        for (int i = 0; i < coordinatesVal.Length - 1; i++)
        {
            coordinatesVal[i] = coordinatesVal[i].Trim();
            coordinatesVal[i] = coordinatesVal[i].Replace(',', ' ');

            numbers.Append(coordinatesVal[i]);

            if (i != coordinatesVal.Length - 1)
            {
                coordinatesVal.Append(", ");
            }

        } 

但是在我看來,這個過程並不是專業的解決方案。 任何人都可以建議更有效的方法嗎?

您的代碼還可以。 您可以關閉臨時結果和鏈式方法調用

var numbers = new StringBuilder();
string[] coordinatesVal = coordinateTxt
    .Trim()
    .Split(new string[] { ",0" }, StringSplitOptions.None);
for (int i = 0; i < coordinatesVal.Length - 1; i++) {
    numbers
        .Append(coordinatesVal[i].Trim().Replace(',', ' '))
        .Append(", ");
}
numbers.Length -= 2;

請注意,最后一條語句假定至少有一個坐標對可用。 如果坐標可以為空,則必須將循環和最后一條語句括在if (coordinatesVal.Length > 0 ) { ... } 這比在循環中包含if更為有效。

您詢問效率,但沒有指定是指代碼效率(執行速度)還是程序員效率(您需要花多少時間)。 專業編程的一個關鍵部分是判斷在任何給定情況下哪一個更為重要。

其他答案很好地解決了程序員的效率問題,因此我在嘗試提高代碼效率。 我在家里這樣做很有趣,但是對於專業工作,在投入時間甚至比較其他答案中給出的方法的速度之前,我需要一個很好的理由,更不用說對其進行改進了。

話雖如此,等待程序完成數百萬個坐標對的轉換會給我一個這樣的理由。

C#字符串處理的速成陷阱之一是String.Replace()String.Trim()返回字符串的全新副本的方式。 這涉及分配內存,復制字符並最終清除生成的垃圾。 這樣做幾百萬次,它開始累加起來。 考慮到這一點,我試圖避免盡可能多的分配和副本。

    enum CurrentField
    {
        FirstNum,
        SecondNum,
        UnwantedZero
    };

    static string ConvertStateMachine(string input)
    {
        // Pre-allocate enough space in the string builder.
        var numbers = new StringBuilder(input.Length);

        var state = CurrentField.FirstNum;
        int i = 0;
        while (i < input.Length)
        {
            char c = input[i++];

            switch (state)
            {
                // Copying the first number to the output, next will be another number
                case CurrentField.FirstNum:
                    if (c == ',')
                    {
                        // Separate the two numbers by space instead of comma, then move on
                        numbers.Append(' ');
                        state = CurrentField.SecondNum;
                    }
                    else if (!(c == ' ' || c == '\n'))
                    {
                        // Ignore whitespace, output anything else
                        numbers.Append(c);
                    }
                    break;

                // Copying the second number to the output, next will be the ,0\n that we don't need
                case CurrentField.SecondNum:
                    if (c == ',')
                    {
                        numbers.Append(", ");
                        state = CurrentField.UnwantedZero;
                    }
                    else if (!(c == ' ' || c == '\n'))
                    {
                        // Ignore whitespace, output anything else
                        numbers.Append(c);
                    }
                    break;
                case CurrentField.UnwantedZero:
                    // Output nothing, just track when the line is finished and we start all over again.
                    if (c == '\n')
                    {
                        state = CurrentField.FirstNum;
                    }
                    break;
            }
        }
        return numbers.ToString();
    }

這使用狀態機根據傳入字符是第一個數字,第二個數字還是行的其余部分來區別對待它們,並相應地輸出字符。 每個字符僅復制一次到輸出中,然后我相信在輸出最后轉換為字符串時再復制一次。 通過使用char[]作為輸出,可以避免第二次轉換。

此代碼中的瓶頸似乎是對StringBuilder.Append()的調用次數。 如果需要更高的速度,我將首先嘗試跟蹤要直接復制到輸出中的字符數,然后使用.Append(string value, int startIndex, int count)在一個調用中發送一個整數。

我將一些示例解決方案放入測試工具,並在包含300,000條坐標對線的字符串上運行它們,平均運行50多次。 我的電腦上的結果是:

String Split, Replace each line (see Olivier's answer, though I pre-allocated the space in the StringBuilder):
    6542 ms / 13493147 ticks, 130.84ms / 269862.9 ticks per conversion
Replace & Trim entire string (see Heriberto's second version):
    3352 ms / 6914604 ticks, 67.04 ms / 138292.1 ticks per conversion
    - Note: Original test was done with 900000 coord pairs, but this entire-string version suffered an out of memory exception so I had to rein it in a bit.
Split and Join (see Łukasz's answer):
    8780 ms / 18110672 ticks, 175.6 ms / 362213.4 ticks per conversion
Character state machine (see above):
    1685 ms / 3475506 ticks, 33.7 ms / 69510.12 ticks per conversion

因此,哪個版本最有效的問題歸結為:您的要求是什么?

您的解決方案很好。 也許您可以像這樣寫得更優雅一些:

string[] coordinatesVal = coordinateTxt.Trim().Split(new string[] { ",0" }, 
StringSplitOptions.RemoveEmptyEntries);
string result = string.Empty;
foreach (string line in coordinatesVal)
{
    string[] numbers = line.Trim().Split(',');
    result += numbers[0] + " " + numbers[1] + ", ";
}
result = result.Remove(result.Count()-2, 2);

請注意Split方法的StringSplitOptions.RemoveEmptyEntries參數,因此您不必在foreach塊中處理空行。

或者,您可以做一個非常短的單線。 難以調試,但在簡單情況下即可完成工作。

string result =
  string.Join(", ",
    coordinateTxt.Trim().Split(new string[] { ",0" }, StringSplitOptions.RemoveEmptyEntries).
      Select(i => i.Replace(",", " ")));

這是無需定義自己的循環和替換方法或使用LINQ的另一種方法。

 string coordinateTxt = @" -82.9494547,36.2913021,0
 -83.0784938,36.2347521,0
 -82.9537782,36.079235,0";

            string[] coordinatesVal = coordinateTxt.Replace(",", "*").Trim().Split(new string[] { "*0", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            string result = string.Join(",", coordinatesVal).Replace("*", " ");
            Console.WriteLine(result);

甚至

            string coordinateTxt = @" -82.9494540,36.2913021,0
-83.0784938,36.2347521,0
-82.9537782,36.079235,0";

            string result = coordinateTxt.Replace(Environment.NewLine, "").Replace($",", " ").Replace(" 0", ", ").Trim(new char[]{ ',',' ' });
            Console.WriteLine(result);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM