45

I have a BitArray with the length of 8, and I need a function to convert it to a byte. How to do it?

Specifically, I need a correct function of ConvertToByte:

BitArray bit = new BitArray(new bool[]
{
    false, false, false, false,
    false, false, false, true
});

//How to write ConvertToByte
byte myByte = ConvertToByte(bit);
var recoveredBit = new BitArray(new[] { myByte });
Assert.AreEqual(bit, recoveredBit);

9 Answers 9

67

This should work:

byte ConvertToByte(BitArray bits)
{
    if (bits.Count != 8)
    {
        throw new ArgumentException("bits");
    }
    byte[] bytes = new byte[1];
    bits.CopyTo(bytes, 0);
    return bytes[0];
}
Sign up to request clarification or add additional context in comments.

6 Comments

Mind: this computes the bits in reverse order, e.g. the BitArray from the example will convert into 128, not 1!
@kornelijepetak: That's just the way that BitArray works, in terms of the way it chooses to copy values.
@kornelijepetak: It is important that it copies in reverse order. If you use BitConverter on other types they are stored in little-endian format.
Its important to draw the distinction between byte endianness and bit endianness. Bit endianness tells you the ordering of the bits in each byte and whether the first bit is the most or least significant bit. Byte endianness tells you the expected order of the bytes in a word. Bit endianess is usually always described as "LSB first" or "MSB first" rather than little-endian or big-endian...
To reverse the order: var reversed = new BitArray(bitArray.Cast<bool>().Reverse().ToArray());
|
39

A bit late post, but this works for me:

public static byte[] BitArrayToByteArray(BitArray bits)
{
    byte[] ret = new byte[(bits.Length - 1) / 8 + 1];
    bits.CopyTo(ret, 0);
    return ret;
}

Works with:

string text = "Test";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(text);
BitArray bits = new BitArray(bytes);
bytes[] bytesBack = BitArrayToByteArray(bits);
string textBack = System.Text.Encoding.ASCII.GetString(bytesBack);
// bytes == bytesBack
// text = textBack

.

7 Comments

Instead of "bits.Length / 8", you should use "(bits.Length - 1) / 8 + 1", otherwise if the BitArray has a length of 7, your byte array will be empty. The "- 1" part makes sure a multiple of 8 will not return plus one. Thanks to stackoverflow.com/questions/17944/…
Good point. A Math.Max(1, bits.Length / 8) will also work I guess (slightly more readable). I always operate on 8 bit bytes so I haven't considered the underflow condition.
@TeddHansen What about 15?
This doesn't handle the empty case, mind - might want to add a check for when bits is empty and return an empty byte[] array accordingly.
I use (bits.Length + 7) >> 3. This will always round up.
|
9

A poor man's solution:

protected byte ConvertToByte(BitArray bits)
{
    if (bits.Count != 8)
    {
        throw new ArgumentException("illegal number of bits");
    }

    byte b = 0;
    if (bits.Get(7)) b++;
    if (bits.Get(6)) b += 2;
    if (bits.Get(5)) b += 4;
    if (bits.Get(4)) b += 8;
    if (bits.Get(3)) b += 16;
    if (bits.Get(2)) b += 32;
    if (bits.Get(1)) b += 64;
    if (bits.Get(0)) b += 128;
    return b;
}

Comments

6

Unfortunately, the BitArray class is partially implemented in .Net Core class (UWP). For example BitArray class is unable to call the CopyTo() and Count() methods. I wrote this extension to fill the gap:

public static IEnumerable<byte> ToBytes(this BitArray bits, bool MSB = false)
{
    int bitCount = 7;
    int outByte = 0;

    foreach (bool bitValue in bits)
    {
        if (bitValue)
            outByte |= MSB ? 1 << bitCount : 1 << (7 - bitCount);
        if (bitCount == 0)
        {
            yield return (byte) outByte;
            bitCount = 8;
            outByte = 0;
        }
        bitCount--;
    }
    // Last partially decoded byte
    if (bitCount < 7)
        yield return (byte) outByte;
}

The method decodes the BitArray to a byte array using LSB (Less Significant Byte) logic. This is the same logic used by the BitArray class. Calling the method with the MSB parameter set on true will produce a MSB decoded byte sequence. In this case, remember that you maybe also need to reverse the final output byte collection.

Comments

5

This should do the trick. However the previous answer is quite likely the better option.

    public byte ConvertToByte(BitArray bits)
    {
        if (bits.Count > 8)
            throw new ArgumentException("ConvertToByte can only work with a BitArray containing a maximum of 8 values");

        byte result = 0;

        for (byte i = 0; i < bits.Count; i++)
        {
            if (bits[i])
                result |= (byte)(1 << i);
        }

        return result;
    }

In the example you posted the resulting byte will be 0x80. In other words the first value in the BitArray coresponds to the first bit in the returned byte.

2 Comments

@Tvde1 result is never left shifted. Bits that are set are individually left shifted the correct amount i and then a bitwise or is done with result. A more verbose way of writing that line is: result = result | ((byte)(1 << i)).
Never mind my comment :)
2

That's should be the ultimate one. Works with any length of array.

private List<byte> BoolList2ByteList(List<bool> values)
    {

        List<byte> ret = new List<byte>();
        int count = 0;
        byte currentByte = 0;

        foreach (bool b in values) 
        {

            if (b) currentByte |= (byte)(1 << count);
            count++;
            if (count == 7) { ret.Add(currentByte); currentByte = 0; count = 0; };              

        }

        if (count < 7) ret.Add(currentByte);

        return ret;

    }

1 Comment

I believe there's a bug here - since count++; has already fired, the next line should be if (count == 8) {...}
1

In addition to @JonSkeet's answer you can use an Extension Method as below:

public static byte ToByte(this BitArray bits)
{
    if (bits.Count != 8)
    {
        throw new ArgumentException("bits");
    }
    byte[] bytes = new byte[1];
    bits.CopyTo(bytes, 0);
    return bytes[0];
}

And use like:

BitArray foo = new BitArray(new bool[]
{
    false, false, false, false,false, false, false, true
});

foo.ToByte();

Comments

0
byte GetByte(BitArray input)
{
  int len = input.Length;
  if (len > 8)
    len = 8;
  int output = 0;
  for (int i = 0; i < len; i++)
    if (input.Get(i))
      output += (1 << (len - 1 - i)); //this part depends on your system (Big/Little)
      //output += (1 << i); //depends on system
  return (byte)output;
}

Cheers!

Comments

0

Little endian byte array converter : First bit (indexed with "0") in the BitArray assumed to represents least significant bit (rightmost bit in the bit-octet) which interpreted as "zero" or "one" as binary.

 public static class BitArrayExtender {

    public static byte[] ToByteArray( this BitArray bits ) {

        const int BYTE = 8;
        int length = ( bits.Count / BYTE ) + ( (bits.Count % BYTE == 0) ? 0 : 1 );
        var bytes  = new byte[ length ];

        for ( int i = 0; i < bits.Length; i++ ) {

           int bitIndex  = i % BYTE;
           int byteIndex = i / BYTE;

           int mask = (bits[ i ] ? 1 : 0) << bitIndex;
           bytes[ byteIndex ] |= (byte)mask;

        }//for

        return bytes;

    }//ToByteArray

 }//class

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.