In this article, we are going to learn about BitArray class in C#, how to create an instance of it, and what its properties and methods are.
We’re also going to learn about the difference between BitArray and bool array.
Let’s start.
What Is a BitArray in C#?
BitArray
class is a type that manages an array of bits. Every bit is represented as a boolean value where the value is true
if the bit is on and false
if the bit is off.
BitArray
implements ICollection
and ICloneable
interfaces.
How to Create a BitArray in C#?
BitArray
class has six constructors that we can use to create a new instance.
BitArray(Int32)
With this constructor, we can initialize a new instance with a specified number of bit values:
BitArray bitArray1 = new BitArray(8); bitArray1.Print(); // False False False False False False False False
The default value is False
.
As you can see, we use the Print
extension method to loop and print elements of BitArray
:
public static void Print(this BitArray bitArray) { foreach (bool bit in bitArray) { Console.Write(bit + " "); } Console.WriteLine(); }
BitArray(Int32, Boolean)
We use this constructor to initialize a new instance with a specified number of bit values and set these values:
BitArray bitArray2 = new BitArray(8, true); bitArray2.Print(); // True True True True True True True True
BitArray(Byte[])
With this constructor, we can initialize a new instance that contains bit values copied from the specified array of bytes:
BitArray bitArray3 = new BitArray(new byte[1] { 2 }); bitArray3.Print(); // False True False False False False False False
We know that one byte equals 8 bits, i.e the value 2
converts to 01000000
, so the second bit is on (True
) and the other bits are off (False
).
BitArray(Int32[])
Using this constructor, we can initialize a new instance that contains bit values copied from the specified array of 32-bit integers:
BitArray bitArray4 = new BitArray(new int[1] { 4 }); bitArray4.Print(); // False False True False False False ...
The value 4
converts to 32 bits: 00100000 00000000 00000000 00000000
, so the third bit is on (True
) and the other bits are off (False
).
BitArray(Boolean[])
If we have an array of booleans that we want to convert to a bit array, we can use this constructor:
BitArray bitArray5 = new BitArray(new bool[8]); bitArray5.Print(); // False False False False False False False False
Although that boolean type takes 8 bits, every value of the boolean array maps to a single value in BitArray
.
BitArray(BitArray)
With this constructor, we can initialize a new instance that contains bit values copied from the specified BitArray
:
BitArray bitArray6 = new BitArray(bitArray1); bitArray6.Print(); // False False False False False False False False
BitArray Properties in C#
Let’s explore the properties of BitArray
and what we can do with them.
Count Property
It enables us to get the number of items in the BitArray
:
BitArray bitArray = new BitArray(8); Console.WriteLine(bitArray.Count); // 8
IsReadOnly Property
We use this property to get a value that specifies whether the BitArray
is read-only:
Console.WriteLine(bitArray.IsReadOnly); // False
This property is required by the ICollection
interface and it’s always false
.
IsSynchronized Property
It enables us to get a value that specifies whether access to the BitArray
is synchronized:
Console.WriteLine(bitArray.IsSynchronized); // False
Same as the previous one, this one is required by the ICollection
interface and it’s always false
.
Indexer
In situations where we want to get or set the value of the bit at a specific index in BitArray
, we can use indexer:
bitArray[0] = true; Console.WriteLine(bitArray[0]); // True
Length Property
With this property, we can get or set the number of items in the BitArray
:
Console.WriteLine(bitArray.Length); // 8 bitArray.Length = 6; Console.WriteLine(bitArray.Length); // 6
This property returns the same value that the Count
property returns, but it can be set to a specific value. On the other hand, the Count
property is read-only.
SyncRoot Property
It enables us to get an object that can be used to synchronize access to the BitArray
:
lock(bitArray.SyncRoot) { foreach (var item in bitArray) { // Insert your code here. } }
BitArray Methods in C#
Let’s explore the main methods of BitArray
and what we can do with them.
Get(Int32)
With this method, we can get the value of the bit at a specific index in the BitArray
:
Console.WriteLine(bitArray.Get(0)); // Equal: Console.WriteLine(bitArray[0]);
Set(Int32, Boolean)
We use this method to set the value of the bit at a specific index in aBitArray
:
bitArray.Set(0, true); // Equal: bitArray[0] = true;
SetAll(Boolean)
If we need to set all bits to the specified value, we can use this method:
bitArray.SetAll(true); bitArray.Print(); // True True True True True True True True
Logical Methods
BitArray
class provides us with many logical operations such as: And
, Or
, Xor
, Not
, LeftShift
, and RightShift
:
BitArray bitArray1 = new BitArray(new bool[] { false, false, true, true }); BitArray bitArray2 = new BitArray(new bool[] { false, true, true, false }); bitArray1.And(bitArray2).Print(); // False False True False // bitArray1 : { False False True False } bitArray1.Or(bitArray2).Print(); // False True True False // bitArray1 : { False True True False } bitArray1.Xor(bitArray2).Print(); // False False False False // bitArray1 : { False False False False } bitArray2.LeftShift(1).Print(); // False False True True // bitArray2 : { False False True True } bitArray2.RightShift(1).Print(); // False True True False
First, we use the And
method to apply the And
operation between two BitArray
objects: bitArray1
and bitArray2
. The And
method returns true
if both bits are true
, otherwise, the result is false
. So in the result, the third bit is true
and the other bits are false
. It also modifies bitArray1
with the result and returns it.
Secondly, we use the Or
method. This method returns false
if both bits are false
, otherwise, the result is true
, so the bitArray1
become False True True False
.
Next, we apply the Xor
method that returns false
if both bits are the same, otherwise, the result is true
. As we can see bitArray1
becomes False False False False
.
Then, we use the LeftShift
method on bitArray2
object. As the name suggests, this method shifts the bits to the left and the empty places become false
.
Finally, we use the RightShift
method on bitArray2
object. This method shifts the bits to the right, and also the empty places become false
.
BitArray vs Bool [] in C#
As we saw, BitArray
class looks similar to bool[]
, but which one should we use?
To answer this question, let’s introduce the BenchmarkDotNet library to compare them:
[MemoryDiagnoser(false)] public class BitArrayBenchmark { [Params(100, 1000_000, 100_000_000)] public int Size { get; set; } [Benchmark] public void BitArray() { BitArray bitArray = new BitArray(Size); for (int i = 0; i < bitArray.Length; i++) { bitArray[i] = true; } } [Benchmark] public void BoolArray() { bool[] boolArray = new bool[Size]; for (int i = 0; i < boolArray.Length; i++) { boolArray[i] = true; } } }
After running the benchmark we can inspect the results:
| Method | Size | Mean | Error | StdDev | Allocated | |---------- |---------- |-----------------:|----------------:|----------------:|------------:| | BitArray | 1000 | 1,580.3 ns | 29.85 ns | 24.93 ns | 184 B | | BoolArray | 1000 | 381.0 ns | 7.39 ns | 10.36 ns | 1024 B | | BitArray | 1000000 | 1,598,289.9 ns | 11,505.53 ns | 9,607.64 ns | 125069 B | | BoolArray | 1000000 | 819,307.9 ns | 11,237.79 ns | 9,962.01 ns | 1000108 B | | BitArray | 100000000 | 157,092,742.3 ns | 2,070,604.76 ns | 1,729,048.75 ns | 12500332 B | | BoolArray | 100000000 | 43,521,267.5 ns | 777,912.09 ns | 864,647.22 ns | 100000373 B |
We notice that BitArray
is memory efficient over bool[]
, because in BitArray
, we need 1 bit to store a value, but in the bool[]
we need 8 bits. This means that bool[]
needs x8
more memory than BitArray
.
On the other hand, bool[]
is faster than BitArray
. This is because of how the values are stored in BitArray
. They are stored inside an array of 32-bit integers. This means doing some processing when setting or getting a value, and this takes more CPU cycles.
Therefore, the decision on which one to use really depends on what we need.
Conclusion
In this article, we’ve learned about the BitArray class in C#, and what its constructors, properties, and methods are. We’ve also compared between BitArray
and bool[]
.
Just use Roaring bitmap, way more efficient