文字列結合の処理方法

StringBuilder

文字列結合について

今回はのテーマは「文字列の結合について」です。
プログラミングをする中で文字列を結合していく時ってありますよね。
私は自作のスマホアプリでhtmlを文字列から生成するために文字列結合を使っています。データを格納しているリストをforeachを使って文字列でhtmlを作成しています。
おそらく文字列の結合といえば「+=」ですよね!
でも実はfor文とかで文字列結合を複数回行うときに「+=」を使うと処理の時間がとても長くなってしまうんです。
そんなときは、StringBuilderを使うんです!!
とドヤ顔で言っていますが、私もつい最近まで知りませんでした(笑)
前回調べたのでここでまとめますね。


どれだけ違う?処理時間

「+=」か「StringBuilder」で処理時間が異なるわけですが、どれだけ違うのでしょうか。
まぁ、ほんの誤差でしょ
そう思いますよね。でもかなり処理時間に差が出るんです!!

というわけで、「+=」を使った文字列結合を行う Test1 というメソッドと、「StringBuilder」を使った文字列結合を行う Test2 というメソッドを作成し、これを呼びだして計算時間を測ります。
公平性を保つために、for文の開始から終わりまでを計測します。
コードは以下のようになっています。

    public static void Test1()
    {
        string str = "a";
        var sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        for(int i=0;i<50000;i++)
        {
            str += "a";
        }
        sw.Stop();
        TimeSpan ts = sw.Elapsed;
        System.Console.WriteLine( "計算時間" + ts );
    }    
    
    public static void Test2()
    {
        StringBuilder sb = new StringBuilder( "a" );
        var sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        for(int i=0;i<50000;i++)
        {
            sb.Append( "a" );
        }
        sw.Stop();
        TimeSpan ts = sw.Elapsed;
        System.Console.WriteLine( "計算時間" + ts );
    }
    

これらを呼び出した結果がこちらです。

ミリ秒の世界ですが、けっこう違いますよね!
と言ってもこれじゃパッとしないので改良します。初期の文字列と追加する文字列を「<p>文字列を追加します。</p>」として、実際に文字列の結合でhtmlを作成する想定で実験してみましょう!
結果がこちらです。
「StringBuilder」はミリ秒に対して、「+=」の方はになっています。
そうなんです!追加する文字列が長いほど大きな差になるんです。
実際のプログラムだと、1文字ではなくある程度の長さの文字列を結合すると思うので処理時間に大きく影響しますよね。


なぜ処理時間に差が出る?

なぜ、「+=」と「StringBuilder」で処理時間に差が出るのでしょうか?
メモリなどに詳しいわけではないのですが、色々調べてみました。
この2つの処理方法ではメモリ使い方が異なるらしく、「StringBuilder」の方が効率よくメモリを使ってくれるらしいです。

具体的には、どう処理しているのか、
おそらく文字列を結合すると考えたら、もともとの文字列の後ろに新しい文字列をくっつけるイメージだと思います。
しかし、「+=」の処理方法は違うんです。以下のようなコードを実行します。

    string str = "a";
    str += "a";
    str += "a";
        
するとメモリでは以下のような処理が行われています。
そう、「+=」は後ろに追加するのではなく、結合した文字列を新しい文字列としてメモリに書き込むのです!
だからfor文などで結合すると、結合するたびにすべての文字列をメモリに書き込むため、繰り返しが行われるほど非効率なんです。

では、「StringBuilder」はどう処理をしているのでしょうか?
また同じように以下のようなコードを実行すると、

    StringBuilder sb = new StringBuilder( "a" );
    sb.Append( "a" );
    sb.Append( "a" );
        
するとメモリでは以下のような処理が行われています。
「StringBuilder」はインスタンス化されたときにある程度のメモリを確保し、今までのイメージ通り新しい文字列はもともとの文字列の後ろに追加されます。
そのためfor文で繰り返しても、追加した分のメモリの書き込みしか行われないため効率がいいんです。


まとめ

というわけで、今回は文字列の結合についてまとめてみました。
今回の実験では、結果を分かりやすくするためにループ回数を多く設定していますが、「+=」と「StringBuilder」では処理時間に差が出ることが分かりましたね!
for文などで文字列を結合するタイミングがどれだけあるかわかりませんが、文字列の結合を繰り返し行うときはStringBuilderを使う!
今回はこの辺で、ではまた!


今回少し話したアプリはこちらです。 メモ帳掲示板

コメント

  1. 面白いですね!

    +=の方がどの言語でも使われているイメージあって早いイメージがありました!

    返信削除
    返信
    1. コメントありがとうございます。
      +=方がよく知られてますからね!ここまで差が出て驚きました。

      削除

コメントを投稿

このブログの人気の投稿

PowerAppsで座席表を作成する

Power AutomateでTeamsのキーワードをトリガーにする

Power Automateで文字列抽出