我刚刚在c# 2.0中写了一个字符串反向函数(即LINQ不可用),然后想到了这个:
public string Reverse(string text)
{
char[] cArray = text.ToCharArray();
string reverse = String.Empty;
for (int i = cArray.Length - 1; i > -1; i--)
{
reverse += cArray[i];
}
return reverse;
}
就我个人而言,我并不喜欢这个功能,我相信有更好的方法来实现它。是吗?
很抱歉在这个旧帖子上发帖。我在为面试练习一些代码。
这是我为c#设计的。在重构之前,我的第一个版本非常糟糕。
static String Reverse2(string str)
{
int strLen = str.Length, elem = strLen - 1;
char[] charA = new char[strLen];
for (int i = 0; i < strLen; i++)
{
charA[elem] = str[i];
elem--;
}
return new String(charA);
}
对比数组。相反的方法下面,它出现更快的12个字符或更少的字符串。13个字符后,数组。倒车开始变得更快,最终在速度上占主导地位。我只是想指出速度开始变化的大致位置。
static String Reverse(string str)
{
char[] charA = str.ToCharArray();
Array.Reverse(charA);
return new String(charA);
}
在字符串中有100个字符时,它比我的版本x 4快。然而,如果我知道字符串总是小于13个字符,我就会使用我所创建的字符串。
测试使用Stopwatch进行,并进行了500万次迭代。此外,我不确定我的版本是否处理代理或组合字符情况与Unicode编码。
因为我喜欢两个答案-一个是使用字符串。创建,因此高性能和低分配和另一个正确性-使用StringInfo类,我决定需要一种组合方法。这是最终的字符串反转方法:)
private static string ReverseString(string str)
{
return string.Create(str.Length, str, (chars, state) =>
{
var enumerator = StringInfo.GetTextElementEnumerator(state);
var position = state.Length;
while (enumerator.MoveNext())
{
var cluster = ((string)enumerator.Current).AsSpan();
cluster.CopyTo(chars.Slice(position - cluster.Length));
position -= cluster.Length;
}
});
}
还有一种更好的方法,使用StringInfo类的方法,它通过只返回索引来跳过Enumerator的大量字符串分配。
private static string ReverseString(string str)
{
return string.Create(str.Length, str, (chars, state) =>
{
var position = 0;
var indexes = StringInfo.ParseCombiningCharacters(state); // skips string creation
var stateSpan = state.AsSpan();
for (int len = indexes.Length, i = len - 1; i >= 0; i--)
{
var index = indexes[i];
var spanLength = i == len - 1 ? state.Length - index : indexes[i + 1] - index;
stateSpan.Slice(index, spanLength).CopyTo(chars.Slice(position));
position += spanLength;
}
});
}
与LINQ解决方案相比的一些基准测试:
String length 20:
LINQ Mean: 2,355.5 ns Allocated: 1440 B
string.Create Mean: 851.0 ns Allocated: 720 B
string.Create with indexes Mean: 466.4 ns Allocated: 168 B
String length 450:
LINQ Mean: 34.33 us Allocated: 22.98 KB
string.Create Mean: 19.13 us Allocated: 14.98 KB
string.Create with indexes Mean: 10.32 us Allocated: 2.69 KB
首先,你必须理解的是str+=将调整字符串内存大小,为1个额外的字符腾出空间。这很好,但是如果你有一本1000页的书,你想要反转,这将需要很长时间来执行。
有些人建议的解决方案是使用StringBuilder。字符串构建器在执行+=时所做的是分配更大的内存块来保存新字符,这样它就不需要在每次添加字符时进行重新分配。
如果你真的想要一个快速和最小的解决方案,我建议如下:
char[] chars = new char[str.Length];
for (int i = str.Length - 1, j = 0; i >= 0; --i, ++j)
{
chars[j] = str[i];
}
str = new String(chars);
在这个解决方案中,在初始化char[]时有一个初始内存分配,在string构造函数从char数组构建字符串时有一个初始内存分配。
在我的系统上,我为您运行了一个测试,反转了一个2750,000个字符的字符串。以下是10次执行的结果:
StringBuilder: 190K - 200K tick
字符数组:130K - 160K
我还运行了一个正常String +=的测试,但我在10分钟后放弃了它,没有输出。
但是,我也注意到,对于较小的字符串,StringBuilder更快,因此您必须根据输入来决定实现。
干杯