[英]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.