【C#入門】配列を結合する方法(文字列要素の連結、処理速度も解説)

配列の結合って使っていますか?

C#の配列の結合には複数の配列の結合配列要素の結合があります。

また、複数の配列を結合する方法についてはいくつか方法があります。

この記事では、配列の結合について

・配列の結合とは
・Array.Copyで結合する方法
・Buffer.BlockCopyで結合する方法

という基本的な内容から、

・AddRangeで結合する方法
・LINQのConcatで結合する方法
・LINQのUnionを使う方法
・配列の文字列要素を結合する方法
・文字列要素を結合する場合の処理速度

など応用的な内容についても解説していきます。

今回は配列の結合について、使い方をわかりやすく解説します!

目次

配列の結合とは

配列の結合と言う場合、大きく分けて2つの場合があります。

複数の配列を結合する場合と、配列要素を結合する場合です。

複数の配列を結合する場合は、LINQを使う方法も含めていくつかの方法があります。

配列要素を結合する方法もいくつか方法があります。

それぞれの方法について、くわしく解説していきます。

複数の配列を結合する方法

複数の配列を結合する方法として、Array.Copyメソッドを使う方法、Buffer.BlockCopyメソッドを使う方法、List型のAddRangeメソッドを使う方法などが挙げられます。

それぞれの使い方について、くわしく解説していきます!

Array.Copyで結合する方法

Array.Copyメソッドは配列をコピーする際に、使うメソッドです。

これを配列の結合のために使用します。

Array.Copyメソッドは配列の範囲を指定してコピーすることができるので、それを利用します。

あらかじめ結合後のサイズの配列を作っておきます。

結合元となる配列をその配列へ範囲を変えてコピーすることで結合することになります。

サンプルコードで確認しましょう。

using System;

namespace Sample
{
  class Sample
  {
    static void Main()
    {
      char[] src1 = {'a', 'b', 'c'};
      char[] src2 = {'d', 'e', 'f'};
      
      char[] dst = new char[src1.Length + src2.Length];
      
      Array.Copy(src1, dst, src1.Length);
      Array.Copy(src2, 0, dst, src1.Length, src2.Length);
      
      Console.WriteLine("[{0}]", string.Join(", ", dst));
      Console.ReadKey();
    }
  }
}

実行結果:

[a, b, c, d, e, f]

このサンプルコードでは、まず結合元の配列src1とsrc2を用意しています。

そして、結合後の配列dstを宣言、定義しています。

配列dstの要素数はsrc1とsrc2の要素数を足し合わせた数です。

まず、Array.Copyメソッドで配列src1をdstにコピーしています。

次に、配列src2をsrc1の後に結合するようにArray.Copyメソッドでコピー先の範囲を指定してdstにコピーしています。

Buffer.BlockCopyで結合する方法

Buffer.BlockCopyメソッドは配列を結合する際によく使われるメソッドです。

ただし、プリミティブ型の配列だけに使用できます。

ちなみに、プリミティブ型とはint型やchar型のようにメソッドを持たない、値を扱う型のことです。

これに対してメソッドを持つクラス型があります。

string型はクラス型になり、Buffer.BlockCopyメソッドを使ってstring型の配列を結合することはできません

また、Buffer.BlockCopyメソッドでは、コピーする位置やコピーするサイズをバイト数で指定します。

それではサンプルコード確認しましょう。

using System;

namespace ArrayCopy
{
  class ArrayCopy
  {
    static void Main()
    {
      char[] src1 = {'a', 'b', 'c'};
      char[] src2 = {'d', 'e', 'f'};
      
      char[] dst = new char[src1.Length + src2.Length];
      
      // 型のサイズを取得
      int size = System.Runtime.InteropServices.Marshal.SizeOf(src1.GetType().GetElementType());
      
      // Buffer.BlockCopyでコピー
      // UTF-8では1文字当たり2バイト
      Buffer.BlockCopy(src1, 0, dst, 0, src1.Length * size * 2);
      Buffer.BlockCopy(src2, 0, dst, src1.Length * size * 2, src2.Length * size * 2);
      
      Console.WriteLine("[{0}]", string.Join(", ", dst));
      Console.ReadKey();
    }
  }
}

実行結果:

[a, b, c, d, e, f]

このサンプルコードでは、Buffer.BlockCopyメソッドを使って配列を結合しています。

結合位置はオフセットのバイト数で指定する必要があり、また配列のサイズのバイト数を指定する必要があります。

使用している文字コードによっては、1文字あたりのバイト数が変わってきますので、注意して指定するようにしましょう!

AddRangeで結合する方法

AddRangeメソッドはList型のオブジェクトを末尾に追加するメソッドです。

したがって、AddRangeメソッドを使って配列を結合するとList型のオブジェクトが出力されます。

出力されたList型のオブジェクトを配列に変換する必要があります。

サンプルコード確認しましょう。

using System;
using System.Collections.Generic;

namespace ArrayCopy
{
  class ArrayCopy
  {
    static void Main()
    {
      char[] src1 = {'a', 'b', 'c'};
      char[] src2 = {'d', 'e', 'f'};
      
      List list = new List(src1.Length + src2.Length);
      
      // 末尾に追加
      list.AddRange(src1);
      list.AddRange(src2);
      
      // 配列に変換
      char[] dst = list.ToArray();
      
      Console.WriteLine("[{0}]", string.Join(", ", dst));
      Console.ReadKey();
    }
  }
}

実行結果:

[a, b, c, d, e, f]

このサンプルコードでは、AddRangeメソッドを使ってList型mのオブジェクトlistの末尾に配列を追加しています。

AddRangeメソッドはList型のオブジェクトを返すので、ToArrayメソッドを使ってList型から配列に変換しています。

LINQを使う場合

LINQを使う場合のメソッドについて解説していきます。

Concatで結合する方法

Concatで結合する方法について、サンプルコードで確認しましょう。

using System;
using System.Linq;

namespace ArrayCopy
{
  class ArrayCopy
  {
    static void Main()
    {
      char[] src1 = {'a', 'b', 'c'};
      char[] src2 = {'d', 'e', 'f'};
      
      char[] dst = src1.Concat(src2).ToArray();
      
      Console.WriteLine("[{0}]", string.Join(", ", dst));
      Console.ReadKey();
    }
  }
}

実行結果:

[a, b, c, d, e, f]

このサンプルコードでは、Concatメソッドを使って配列を結合しています。

ConcatはIEnumerable型のオブジェクトを返すので、ToArrayメソッドで配列に変換しています。

ちなみにIEnumerableとはインターフェース名で、これを実装するとforereachを使って処理することができます。

配列やListはこのIEnumerableインターフェースを実装しています。

Unionを使う方法

配列を結合する方法としてUnionメソッドを使う方法があります。

ただし、Unionメソッドは要素が重複しないように結合します。

サンプルコードで確認しましょう。

using System;
using System.Linq;

namespace ArrayCopy
{
  class ArrayCopy
  {
    static void Main()
    {
      char[] src1 = {'a', 'b', 'c'};
      char[] src2 = {'c', 'd', 'e'};
      
      char[] dst = src1.Union(src2).ToArray();
      
      Console.WriteLine("[{0}]", string.Join(", ", dst));
      Console.ReadKey();
    }
  }
}

実行結果:

[a, b, c, d, e]

このサンプルコードでは、Unionメソッドを使って配列を結合しています。

結合元の配列src1、src2では要素’c’が重複しています。

しかし、Unionメソッドで結合しているので結合後の配列dstでは要素’c’は1個だけ格納されています。

UnionメソッドもConcatメソッドと同じようにIEnumerable型のオブジェクトを返すので、ToArrayメソッドで配列に変換しています。

配列の文字列要素を結合する方法

これまでは、複数の配列を結合する方法についてお伝えしてきました。

配列では文字列要素を結合する場合もあります。

この場合、stringクラスのJoinメソッドを使います。

Joinメソッドは以下のように記述します。

public static string Join(
    string separator,
    params string[] value
)

引数 separatorでは、文字列要素を結合する場合の区切り文字列を指定します。

引数 valueには、文字列要素を格納している配列を指定します。

サンプルコードで確認しましょう。

using System;
using System.Linq;

namespace ArrayCopy
{
  class ArrayCopy
  {
    static void Main()
    {
      char[] src = {'a', 'b', 'c'};
      
      Console.WriteLine("{0}", string.Join("/", src));
      Console.ReadKey();
    }
  }
}

実行結果:

a/b/c

サンプルコードでは、Joinメソッドを使って、区切り文字列に”/”を指定して配列srcの要素を結合しています。

文字列要素を結合する場合の処理速度

先ほどは配列の文字列要素を結合する方法についてお伝えしました。

文字列を結合する方法として、「+=」記号を使う方法や、配列のJoinメソッドを使う方法、StringBuilderクラスを使うを使う方法などがあります。

結合する文字列の数が少ない場合はどれを使っても構わないと思いますが、数が多い場合は処理速度が影響するかもしれません。

そこで、それぞれの方法で処理速度を計測して比較してみましょう。

速度の計測にはStopwatchクラスを使用します。

using System;
using System.Diagnostics;
using System.Text;

namespace ArrayCopy
{
    class ArrayCopy
    {
        static void Main()
        {
            Stopwatch sw = new Stopwatch();
            long nums = 10000;
            string str = null;

            sw.Start();
            for (int i = 0; i < nums; i++) {
                str += 'a';
            }
            sw.Stop();
            Console.WriteLine("「+=」では{0}ミリ秒", sw.Elapsed.TotalMilliseconds);

            str = null;
            sw.Start();
            char[] src = new char[nums];
            for (int i = 0; i < nums; i++) {
                src[i] = 'a';
            }
            str = string.Join("", src);
            sw.Stop();
            Console.WriteLine("string.Joinでは{0}ミリ秒", sw.Elapsed.TotalMilliseconds);

            str = null;
            sw.Start();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < nums; i++) {
                sb.Append('a');
            }
            str = sb.ToString();
            sw.Stop();
            Console.WriteLine("StringBuilder.Appendでは{0}ミリ秒", sw.Elapsed.TotalMilliseconds);

            Console.ReadKey();
        }
    }
}

実行結果:

「+=」では138.5593ミリ秒
string.Joinでは140.5661ミリ秒
StringBuilder.Appendでは140.649ミリ秒

このサンプルコードでは、それぞれの方法を1万回繰り返すのにかかった時間をDiagnostics.Stopwatchクラスを使って計測しています。

いずれの方法でも、明らかな差はないようです。

まとめ

ここでは、配列の結合について説明しました。

複数の配列を結合する方法として、Array.Copyメソッドを使う方法、Buffer.BlockCopyを使う方法、AddRangeメソッドを使う方法の3つの方法についてお伝えしました。

それぞれ使い方が異なりますので、目的に合わせて使い分けるようにしましょう。

また、配列の文字列要素を結合する方法として、Joinメソッドを使う方法についてお伝えしました。

使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次