1. ホーム
  2. c#

[解決済み】C#で2つ以上のバイト配列を結合する最良の方法

2022-04-03 22:24:05

質問

C#で3つのバイト配列があり、1つにまとめる必要があります。このタスクを完了するための最も効率的な方法は何でしょうか?

どのように解決するのですか?

プリミティブ型(バイトを含む)の場合は System.Buffer.BlockCopy の代わりに System.Array.Copy . より速くなりました。

10バイトずつの配列を3つ使って100万回実行するループで、提案された各方法の時間を計ってみました。以下はその結果です。

  1. を使用した新しいバイト配列 System.Array.Copy - 0.2187556秒
  2. を使用した新しいバイト配列 System.Buffer.BlockCopy - 0.1406286秒
  3. IEnumerable<byte> をC#のyield演算子で使用する - 0.0781270秒
  4. IEnumerable<byte> LINQのConcat<>を使用 - 0.0781270秒

各配列のサイズを100要素に増やして、テストを再実行しました。

  1. を使用した新しいバイト配列 System.Array.Copy - 0.2812554秒
  2. を使用した新しいバイト配列 System.Buffer.BlockCopy - 0.2500048秒
  3. IEnumerable<byte> をC#のyield演算子で使用 - 0.0625012秒
  4. IEnumerable<byte> LINQのConcat<>を使用 - 0.0781265秒

各配列のサイズを1000要素に増やして、テストを再実行しました。

  1. を使用した新しいバイト配列 System.Array.Copy - 1.0781457秒
  2. を使用した新しいバイト配列 System.Buffer.BlockCopy - 1.0156445秒
  3. IEnumerable<byte> をC#のyield演算子で使用 - 0.0625012秒
  4. IEnumerable<byte> LINQのConcat<>を使用 - 0.0781265秒

最後に、各配列のサイズを100万要素まで増やし、各ループを実行しながらテストを再実行しました。 のみ 4000回。

  1. を使用した新しいバイト配列 System.Array.Copy - 13.4533833秒
  2. を使用した新しいバイト配列 System.Buffer.BlockCopy - 13.1096267秒
  3. IEnumerable<byte> をC#のyield演算子で使用する - 0秒
  4. IEnumerable<byte> LINQのConcat<>を使用する - 0秒

したがって、新しいバイト配列が必要な場合は、次のようにします。

byte[] rv = new byte[a1.Length + a2.Length + a3.Length];
System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length);
System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length);
System.Buffer.BlockCopy(a3, 0, rv, a1.Length + a2.Length, a3.Length);

しかし、もし IEnumerable<byte> , 間違いなく は、LINQのConcat<>メソッドの方が好きです。C#のyield演算子より少し遅いだけで、より簡潔で、よりエレガントです。

IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);

任意の数の配列があり、.NET 3.5を使用している場合、その配列を System.Buffer.BlockCopy の解決策をより汎用的にするために、次のようにします。

private byte[] Combine(params byte[][] arrays)
{
    byte[] rv = new byte[arrays.Sum(a => a.Length)];
    int offset = 0;
    foreach (byte[] array in arrays) {
        System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
        offset += array.Length;
    }
    return rv;
}

*注:上記のブロックが動作するためには、次の名前空間を先頭に追加する必要があります。

using System.Linq;

Jon Skeetの、後続のデータ構造(バイト配列対IEnumerable<byte>)の反復に関する指摘に対して、私は最後のタイミングテスト(100万要素、4000反復)を再実行し、各パスで配列全体にわたって反復するループを追加しました。

  1. を使用した新しいバイト配列 System.Array.Copy - 78.20550510秒
  2. を使用した新しいバイト配列 System.Buffer.BlockCopy - 77.89261900秒
  3. IEnumerable<byte> C#のyield演算子を使用 - 551.7150161秒
  4. IEnumerable<byte> LINQのConcat<>を使用する - 448.1804799 秒

要は、それは VERY の両方の効率性を理解することが重要です。 と使用方法 のデータ構造です。作成時の効率に注目するだけでは、使用時の非効率性を見落としてしまう可能性があるのです。ジョン、ありがとうございます。