前回は文字列を分割する方法を紹介したので、今回は分割されているものを結合する方法を紹介します。
+ と += 演算子で結合させる
単純に二つの文字列を結合させるだけなら
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using System; class Program { static void Main() { string str1 = "Hello "; string str2 = "C# World!!"; string str = str1 + str2; Console.WriteLine(str); // "Hello C# World!!"と出力される } } |
C#は足し算をする感覚で文字列を結合させることができるのでいいですね。これがC言語だと面倒なことになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main() { char str1[] = "Hello "; char str2[] = "C# World!!"; char str[17] = ""; // 連結されたあとの文字数+1以上の値にしないと実行時エラーとなる strcpy(str, str1); // str = str1 + str2;のようなデタラメを書くとエラーになる strcat(str, str2); printf(str); } |
もしC言語で挫折したかたはC#をお試しください。初心者にはC#がおすすめです。
もし結合させたい文字列がすでに配列内に格納されているのであればどうでしょうか?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System; class Program { static void Main() { string[] vs = { "Hello ", "C# World!!" }; string str = ""; foreach (string s in vs) str += s; Console.WriteLine(str); } } |
この方法はあまりよくありません。理由は時間がかかるからです。この例では配列の要素数は2なので別に問題ないといえば問題ないのですが、配列の要素数が大きい場合は時間がかかります。+= でつなげていく方法は文字列の最後を調べないといけないのでそのぶん時間がかかるのです。扱う文字列が長くなると処理にかかる時間は「配列の要素数に比例して」ではなく、それ以上にかかるようになります。
StringBuilderを使う
StringBuilderを使うと += でつなげていく方法とは比較にならないくらい短時間で文字列の連結ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System; using System.Text; class Program { static void Main() { string[] vs = { "Hello ", "C# World!!" }; StringBuilder sb = new StringBuilder(); foreach (string s in vs) sb.Append(s); Console.WriteLine(sb.ToString()); // "Hello C# World!!"と出力される } } |
String.Joinメソッドを使う
すでに連結したい文字列が配列として準備されているのであれば、String.Joinメソッドを使う方法もあります。
1 2 3 4 5 6 7 8 9 10 |
using System; class Program { static void Main() { string[] vs = { "Hello ", "C# World!!" }; Console.WriteLine(String.Join("", vs)); // "Hello C# World!!"と出力される } } |
String.Joinメソッドの第一引数は連結するときに間にいれる文字列を指定します。間になにもいれずに連結するのであれば””を渡します。配列内の文字列を半角スペース区切りやカンマ区切りで出力したいときはString.Joinメソッドが一番便利かもしれません。
1 2 3 4 5 6 7 8 9 10 |
using System; class Program { static void Main() { string[] vs = { "Hello", "C#", "World!!" }; Console.WriteLine(String.Join(" ", vs)); // "Hello C# World!!"と出力される } } |
1 2 3 4 5 6 7 8 9 10 |
using System; class Program { static void Main() { int[] vs = { 1, 2, 3 }; Console.WriteLine(String.Join(",", vs)); // "1,2,3"と出力される } } |
速いのはどれか?
処理にかかる時間が一番短いのはどれでしょうか? 要素数が多い文字列の配列を用意して実際に時間を計測してみます。
時間を計測するのであれば
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Program { static void Main() { var sw = new System.Diagnostics.Stopwatch(); sw.Start(); // ここに処理を書く sw.Stop(); Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒"); // 処理にかかった時間がわかる } } |
まず、文字列の配列を生成するメソッドを作成します。そして最初は+=で連結した場合の処理時間を計測してみました。
配列の要素数が10000のときは62ミリ秒かかりました。これを倍の20000に増やすと246ミリ秒もかかりました。倍に増やすと処理に必要な時間は2倍どころかそれを大きく上回る結果になりました。大量のデータを扱うときはこの方法はあまりおすすめできないということになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System; using System.Collections.Generic; class Program { static string[] CreateArray() { List<string> vs = new List<string>(); for (int i = 0; i < 10000; i++) vs.Add("abc"); return vs.ToArray(); } static void Main() { var sw = new System.Diagnostics.Stopwatch(); sw.Start(); string[] vs = CreateArray(); string str = ""; foreach (string s in vs) str += s; sw.Stop(); Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒"); } } |
ではStringBuilderを用いた方法とString.Joinメソッドを用いる方法ではどちらが速いのでしょうか? 配列の要素数を100万まで増やしてもStringBuilderを用いた場合は64ミリ秒しかかかりません。String.Joinメソッドを用いた場合はさらに短く48ミリ秒で処理がおわります。