文字列を連結する最も効率的な方法は何ですか?
17 に答える
.NET パフォーマンスの第一人者であるRico Marianiは、まさにこの主題に関する記事を書いています。疑うほど単純ではありません。基本的なアドバイスは次のとおりです。
パターンが次のようになっている場合:
x = f1(...) + f2(...) + f3(...) + f4(...)
それは1つの連結であり、それは気の利いたものです.StringBuilderはおそらく役に立たないでしょう.
パターンが次のようになっている場合:
if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)
その場合は、おそらく StringBuilder が必要です。
この主張を裏付けるさらに別の記事は、Eric Lippert によるもので、1 行の+
連結に対して実行される最適化について詳細に説明しています。
この方法は、演算子StringBuilder.Append()
を使用するよりもはるかに優れています。しかし、1000 以下の連結を実行する場合は、よりもさらに効率的で+
あることがわかりました。String.Join()
StringBuilder
StringBuilder sb = new StringBuilder();
sb.Append(someString);
唯一の問題String.Join
は、文字列を共通の区切り文字で連結する必要があることです。
編集: @ryanversawが指摘したように、 delimiter を作成できますstring.Empty
。
string key = String.Join("_", new String[]
{ "Customers_Contacts", customerID, database, SessionID });
文字列連結には 6 種類あります。
- プラス (
+
) 記号を使用します。 - を使用し
string.Concat()
ます。 - を使用し
string.Join()
ます。 - を使用し
string.Format()
ます。 - を使用し
string.Append()
ます。 - を使用し
StringBuilder
ます。
実験でstring.Concat()
は、単語が (およそ) 1000 未満の場合はアプローチするのが最善の方法であることが証明されており、単語が 1000 を超える場合はStringBuilder
使用する必要があります。
詳細については、このサイトを確認してください。
string.Join() vs string.Concat()
ここでの string.Concat メソッドは、区切り文字を空にして string.Join メソッドを呼び出した場合と同じです。空の文字列を追加するのは高速ですが、追加しないとさらに高速になるため、ここではstring.Concatメソッドが優れています。
Chinh Doから- StringBuilder は常に高速であるとは限りません。
経験則
3 つ以下の動的文字列値を連結する場合は、従来の文字列連結を使用します。
3 つ以上の動的文字列値を連結する場合は、 を使用します
StringBuilder
。複数の文字列リテラルから大きな文字列を作成する場合は、
@
文字列リテラルまたはインライン + 演算子を使用します。
ほとんどのStringBuilder
場合は最善の策ですが、その投稿に示されているように、少なくともそれぞれの状況について考える必要がある場合があります。
ループで操作している場合StringBuilder
は、おそらく行く方法です。新しい文字列を定期的に作成するオーバーヘッドを節約できます。ただし、一度しか実行されないコードでは、String.Concat
おそらく問題ありません。
しかし、Rico Mariani (.NET 最適化の第一人者)がクイズを作成し、最後に、ほとんどの場合、.NET を推奨すると述べていString.Format
ます。
このMSDNの記事から:
StringBuilder オブジェクトの作成に関連して、時間とメモリの両方でオーバーヘッドが発生します。メモリが高速なマシンでは、約 5 つの操作を行う場合に StringBuilder が役立ちます。経験則として、10 回以上の文字列操作は、低速のマシンであっても、どのマシンでもオーバーヘッドの正当な理由になると言えます。
したがって、MSDN を信頼する場合は、10 個を超える文字列操作/連結を行う必要がある場合は StringBuilder を使用します。それ以外の場合は、'+' を使用した単純な文字列連結で問題ありません。
他の回答に加えて、StringBuilder に割り当てるメモリの初期量を伝えることができることに注意してください。
capacityパラメータは、現在のインスタンスによって割り当てられたメモリに格納できる最大文字数を定義します。その値は、Capacityプロパティに割り当てられます。現在のインスタンスに格納される文字数がこの容量値を超える場合、StringBuilder オブジェクトはそれらを格納するために追加のメモリを割り当てます。
容量がゼロの場合、実装固有のデフォルト容量が使用されます。
事前に割り当てられていない StringBuilder に繰り返し追加すると、通常の文字列を繰り返し連結するのと同じように、多くの不要な割り当てが発生する可能性があります。
最終的な文字列の長さがわかっている場合、それを自明に計算できる場合、または一般的なケースについて知識に基づいた推測を行うことができる場合 (多くの文字列を割り当てることは必ずしも悪いことではありません)、この情報をコンストラクターまたは容量プロパティ。特にパフォーマンス テストを実行して、StringBuilder を内部で同じことを行う String.Concat などの他のメソッドと比較する場合。比較に StringBuilder の事前割り当てが含まれていない、オンラインで表示されるテストはすべて間違っています。
サイズについて推測できない場合は、事前割り当てを制御するための独自のオプションの引数を持つユーティリティ関数を作成している可能性があります。
文字列リテラル+
を連結する場合は、演算子を使用する必要があることを指摘することも重要です。
+ 演算子を使用して文字列リテラルまたは文字列定数を連結すると、コンパイラは 1 つの文字列を作成します。ランタイム連結は発生しません。
System.String は不変です。文字列変数の値を変更すると、新しいメモリが新しい値に割り当てられ、以前のメモリ割り当てが解放されます。System.StringBuilder は、変更された文字列に個別のメモリ ロケーションを割り当てずにさまざまな操作を実行できる可変文字列の概念を持つように設計されています。
最も効率的なのは、次のように StringBuilder を使用することです。
StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();
@jonezy: String.Concat は、いくつかの小さなことがあれば問題ありません。しかし、メガバイト単位のデータを連結している場合、プログラムは失敗する可能性があります。
それは本当にあなたの使用パターンに依存します。string.Join、string、Concat、string.Formatの詳細なベンチマークは、次の場所にあります。String.Formatは集中ログには適していません
(これは実際に私がこの質問に与えたのと同じ答えです)
文字列が 2 つだけの場合は、StringBuilder を使用したくないことは間違いありません。StringBuilder のオーバーヘッドが複数の文字列を割り当てるオーバーヘッドよりも小さくなるしきい値があります。
したがって、文字列が 2 ~ 3 個を超える場合は、DannySmurf のコードを使用します。それ以外の場合は、+ 演算子を使用してください。
コードにもよるでしょう。一般的には StringBuilder の方が効率的ですが、いくつかの文字列を連結するだけで、すべてを 1 行で行う場合は、コードの最適化によって処理される可能性があります。コードがどのように見えるかについても考えることが重要です。大きなセットの場合、StringBuilder は読みやすくなりますが、小さなセットの場合、StringBuilder は不要な混乱を追加するだけです。