Convert from BitArray to Byte
Asked Answered
S

9

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);
Semen answered 18/2, 2009 at 7:13 Comment(0)
S
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];
}
Southeaster answered 18/2, 2009 at 7:17 Comment(6)
Mind: this computes the bits in reverse order, e.g. the BitArray from the example will convert into 128, not 1!Streusel
Why does this happen in a reverse order?Matheny
@kornelijepetak: That's just the way that BitArray works, in terms of the way it chooses to copy values.Southeaster
@kornelijepetak: It is important that it copies in reverse order. If you use BitConverter on other types they are stored in little-endian format.Previous
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...Keyway
To reverse the order: var reversed = new BitArray(bitArray.Cast<bool>().Reverse().ToArray());Paynim
R
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

.

Relation answered 6/1, 2011 at 20:4 Comment(7)
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 #18444Kurdistan
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.Relation
@TeddHansen What about 15?Flyback
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.Kaenel
Should be "byte[(bits.Length - 1) / 8 - 1", otherwise adding unnecessary "0" byte end of byte array.Octosyllabic
The requirement here is that bits.Length / 8 should round up, hence it should be (int)Math.Ceiling[bits.Length / 8]. We can simply this because we know that bits.Length is a positive integer: (bits.Length + 8 - 1) / 8 == (bits.Length + 7) / 8. For bits.Length == 0, the formula conveniently returns 0.Mitsue
I use (bits.Length + 7) >> 3. This will always round up.Ikeda
S
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;
}
Streusel answered 18/2, 2009 at 7:45 Comment(0)
B
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.

Brewton answered 1/12, 2017 at 11:22 Comment(0)
C
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.

Catafalque answered 18/2, 2009 at 7:28 Comment(2)
@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)).Catafalque
Never mind my comment :)Wini
C
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;

    }
Cosmonautics answered 30/7, 2011 at 21:28 Comment(1)
I believe there's a bug here - since count++; has already fired, the next line should be if (count == 8) {...}Syncrisis
F
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();
Francisfrancisca answered 5/7, 2017 at 8:57 Comment(0)
H
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!

Hukill answered 25/4, 2013 at 22:22 Comment(0)
D
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
Duncan answered 25/10, 2014 at 19:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.