bool[] flags = new bool[8] は 8 つの真偽値を格納できますが、1 要素が内部的に 1 バイト以上占有します。これを 1 バイト(byte)の各ビットに詰め込むことで、メモリを節約しつつビット演算の練習にもなります。これをビットパッキングと呼びます。
bool[] と byte の対応関係を理解できるBitArray クラスの存在を知っているbyte は 8 ビットで、各ビットを独立したフラグとして扱えます。
ビット 7 が bool[0](最上位ビット)、ビット 0 が bool[7](最下位ビット)に対応させます。
bool 配列を byte に変換するには、各要素が true のときに対応ビットを OR で立てます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bool[] flags = { true, false, true, false, false, true, false, true };
byte Pack(bool[] flags)
{
byte result = 0;
for (int i = 0; i < 8; i++)
{
if (flags[i])
{
result |= (byte)(1 << (7 - i)); // ビット (7-i) を立てる
}
}
return result;
}
byte packed = Pack(flags);
Console.WriteLine(packed); // 165
Console.WriteLine($"0b{Convert.ToString(packed, 2).PadLeft(8, '0')}");
// 0b10100101
ポイント:
1 << (7 - i) で i 番目の要素に対応するビットマスクを作る|= で該当ビットだけを 1 にする(byte) にキャストするのは << の結果が int になるためbyte から bool 配列に戻すには、各ビット位置を AND マスクで確認します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool[] Unpack(byte packed)
{
bool[] result = new bool[8];
for (int i = 0; i < 8; i++)
{
result[i] = (packed & (1 << (7 - i))) != 0;
}
return result;
}
bool[] restored = Unpack(packed);
foreach (bool b in restored)
{
Console.Write(b ? "T " : "F ");
}
// T F T F F T F T
ポイント:
packed & (1 << (7 - i)) でビット i が立っているか確認0 でなければ truePack → Unpack を経ても元の配列が復元されることを確認します。
1
2
3
4
5
6
7
8
9
10
11
bool[] original = { true, false, true, false, false, true, false, true };
byte packed = Pack(original);
bool[] restored = Unpack(packed);
for (int i = 0; i < 8; i++)
{
Console.WriteLine($"[{i}] {original[i]} -> {restored[i]} {(original[i] == restored[i] ? "✓" : "✗")}");
}
// [0] True -> True ✓
// [1] False -> False ✓
// ...
System.Collections.BitArray を使うと、同様の操作をより簡単に行えます。
1
2
3
4
5
6
7
8
using System.Collections;
var bits = new BitArray(new bool[] { true, false, true, false, false, true, false, true });
// byte に変換
byte[] bytes = new byte[1];
bits.CopyTo(bytes, 0);
Console.WriteLine(bytes[0]); // 165(環境により LSB/MSB の順が異なる場合あり)
BitArray は AND・OR・XOR 演算をそのままメソッドで呼び出せる便利なクラスです。ただし、ビット順(LSB/MSB)や動作の細かい違いがあるため、本ページで紹介した手動実装の仕組みを先に理解しておくと応用が効きます。
bool[8] は byte の 8 ビットと 1 対 1 で対応させられる|= (byte)(1 << (7 - i)) で真のビットを立てる& (1 << (7 - i)) != 0 でビットが立っているか確認するBitArray を使うと同様の操作を簡潔に書けるflags = { false, false, false, false, true, true, true, true } を Pack するといくつになりますか?
byte packed = 0b11110000 を Unpack すると result[4] はどうなりますか?
ビット 3〜0 が立ちます。0b00001111 = 15 です。
ビット 3(1 << (7-4) = 1 << 3 = 8)は 0b11110000 & 8 = 0 なので false です。
多次元配列 では、行列形式のデータを 2 次元配列で扱う方法を学びます。