文字列を逆順にする(「あいう」→「ういあ」みたいな意味)ときにLINQを使うというネタがある。
// string text; public string ReverseByLINQ() => new(text.Reverse().ToArray());
ネタというのは、LINQは分かりやすくて書きやすいけれどパフォーマンスと天秤、みたいな感じで出る話題的な意味。
(※ と思ったけれど記事化にあたりググったところ、普通に単一の手段として紹介しているサイトが複数あった。別にそういう捉え方はされていなかったかもしれない)
文字列の取り扱いの注意点も盛り込める。
public string ReverseByStringConcat() => text.Reverse().Aggregate("", (str, c) => str + c);
こういうことをすると毎回文字列が new されちゃうよね、というネタ。
ネタ以外では?
文字列はStringBuilder
が王道という雰囲気。
Reverse()
もやめて、愚直にループ。
public string ReverseByStringBuilder() { StringBuilder sb = new(text.Length); for (int i = text.Length - 1; i >= 0; i--) { sb.Append(text[i]); } return sb.ToString(); }
連続したメモリへの操作ということでSpan
も。
public string ReverseBySpanReverse() { var span = text.AsSpan(); Span<char> buf = stackalloc char[span.Length]; span.CopyTo(buf); buf.Reverse(); return buf.ToString(); }
ループしてもよいけれど、Span
にはReverse()
がある。これは内部で、先頭と末尾から参照を交換していくunsafe
な処理をしている。
というわけでBenchmarkDotNet。
string text = "あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。";
Method | Mean | Error | StdDev | Gen0 | Allocated | ----------------------- |-------------:|------------:|-----------:|-------:|----------:| ReverseByLINQ | 704.153 ns | 98.8347 ns | 5.4175 ns | 0.2728 | 856 B | ReverseByStringConcat | 2,786.224 ns | 315.3830 ns | 17.2872 ns | 2.6054 | 8176 B | ReverseByStringBuilder | 175.187 ns | 20.1415 ns | 1.1040 ns | 0.1147 | 360 B | ReverseBySpanReverse | 48.673 ns | 7.7572 ns | 0.4252 ns | 0.0485 | 152 B |
やはりアロケーションや、ライブラリが内部でやっていることの関係でSpan
が強かった。
ところで、Reverse()
は副作用のあるメソッドなので、ReadOnlySpan<char>
には生えていない。
これが許されたら、不変として扱われるstring
が書き換わってしまう。マネージドで安全なC#では許されようはずがない。
―― まぁちょっとくらいなら……
public string ReverseDestructive() { var readOnlySpan = text.AsSpan(); var span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(readOnlySpan), readOnlySpan.Length); span.Reverse(); return text; // 書き換わっている }
Method | Mean | Error | StdDev | Gen0 | Allocated | ----------------------- |-------------:|-----------:|----------:|-------:|----------:| ReverseDestructive | 9.093 ns | 0.7682 ns | 0.0421 ns | - | - |
実用性はないので、文字列を逆順にするネタとして。