将 bool[] 转换为 byte[]

Posted

技术标签:

【中文标题】将 bool[] 转换为 byte[]【英文标题】:Convert bool[] to byte[] 【发布时间】:2010-10-17 07:36:39 【问题描述】:

我有一个List<bool>,我想将其转换为byte[]。我该怎么做呢? list.toArray() 创建一个 bool[]

【问题讨论】:

你想让 3 个布尔值变成 1 个字节还是 3 个字节? 【参考方案1】:

IEnumerable 方法AnorZaken's answer:

static IEnumerable<byte> PackBools(IEnumerable<bool> bools)

    int bitIndex = 0;
    byte currentByte = 0;
    foreach (bool val in bools) 
        if (val)
            currentByte |= (byte)(1 << bitIndex);
        if (++bitIndex == 8) 
            yield return currentByte;
            bitIndex = 0;
            currentByte = 0;
        
    
    if (bitIndex != 8) 
        yield return currentByte;
    

以及相应的解包,其中paddingEnd 表示从要解包的最后一个字节丢弃的位数:

static IEnumerable<bool> UnpackBools(IEnumerable<byte> bytes, int paddingEnd = 0)

    using (var enumerator = bytes.GetEnumerator()) 
        bool last = !enumerator.MoveNext();
        while (!last) 
            byte current = enumerator.Current;
            last = !enumerator.MoveNext();
            for (int i = 0; i < 8 - (last ? paddingEnd : 0); i++) 
                yield return (current & (1 << i)) != 0;
            
        
    

【讨论】:

好代码。它似乎确实有一个错误/错别字,但是在 PackBools() 中它读取 if (bitIndex != 8),但它永远不能 == 8,因为上面的代码已经检查了这个条件 if (++bitIndex == 8)并设置 bitIndex = 0。因此它可能应该读取 if (bitIndex != 0) 作为下一个新字节的开头。【参考方案2】:

Marc 的回答已经很好了,但是……

假设你是那种喜欢玩比特币的人,或者只是想写更少的代码并且挤出更多的性能,那么这里的代码是给你的好先生/女士:

byte[] PackBoolsInByteArray(bool[] bools)

    int len = bools.Length;
    int bytes = len >> 3;
    if ((len & 0x07) != 0) ++bytes;
    byte[] arr2 = new byte[bytes];
    for (int i = 0; i < bools.Length; i++)
    
        if (bools[i])
            arr2[i >> 3] |= (byte)(1 << (i & 0x07));
    

它与 Marc 的代码完全相同,只是更简洁。

当然,如果我们真的想全力以赴,我们也可以展开... ...当我们在它的时候,让我们在返回类型上扔一个曲线球!

IEnumerable<byte> PackBoolsInByteEnumerable(bool[] bools)

    int len = bools.Length;
    int rem = len & 0x07; // hint: rem = len % 8.

    /*
    byte[] byteArr = rem == 0 // length is a multiple of 8? (no remainder?)
        ? new byte[len >> 3] // -yes-
        : new byte[(len >> 3)+ 1]; // -no-
     */

    const byte BZ = 0,
        B0 = 1 << 0, B1 = 1 << 1, B2 = 1 << 2, B3 = 1 << 3,
        B4 = 1 << 4, B5 = 1 << 5, B6 = 1 << 6, B7 = 1 << 7;

    byte b;
    int i = 0;
    for (int mul = len & ~0x07; i < mul; i += 8) // hint: len = mul + rem.
    
        b = bools[i] ? B0 : BZ;
        if (bools[i + 1]) b |= B1;
        if (bools[i + 2]) b |= B2;
        if (bools[i + 3]) b |= B3;
        if (bools[i + 4]) b |= B4;
        if (bools[i + 5]) b |= B5;
        if (bools[i + 6]) b |= B6;
        if (bools[i + 7]) b |= B7;

        //byteArr[i >> 3] = b;
        yield return b;
    

    if (rem != 0) // take care of the remainder...
    
        b = bools[i] ? B0 : BZ; // (there is at least one more bool.)

        switch (rem) // rem is [1:7] (fall-through switch!)
        
            case 7:
                if (bools[i + 6]) b |= B6;
                goto case 6;
            case 6:
                if (bools[i + 5]) b |= B5;
                goto case 5;
            case 5:
                if (bools[i + 4]) b |= B4;
                goto case 4;
            case 4:
                if (bools[i + 3]) b |= B3;
                goto case 3;
            case 3:
                if (bools[i + 2]) b |= B2;
                goto case 2;
            case 2:
                if (bools[i + 1]) b |= B1;
                break;
            // case 1 is the statement above the switch!
        

        //byteArr[i >> 3] = b; // write the last byte to the array.
        yield return b; // yield the last byte.
    

    //return byteArr;

提示: 如您所见,我包含了将 byte[] 作为 cmets 返回的代码。如果这是您想要/需要的,只需注释掉这两个 yield 语句即可。


小提示: 转移x &gt;&gt; 3 更便宜x / 8。 屏蔽x &amp; 0x07 更便宜x % 8。 屏蔽x &amp; ~0x07x - x % 8 更便宜。


编辑: 以下是一些示例文档:

    /// <summary>
    /// Bit-packs an array of booleans into bytes, one bit per boolean.
    /// </summary><remarks>
    /// Booleans are bit-packed into bytes, in order, from least significant
    /// bit to most significant bit of each byte.<br/>
    /// If the length of the input array isn't a multiple of eight, then one
    /// or more of the most significant bits in the last byte returned will
    /// be unused. Unused bits are zero / unset.
    /// </remarks>
    /// <param name="bools">An array of booleans to pack into bytes.</param>
    /// <returns>
    /// An IEnumerable&lt;byte&gt; of bytes each containing (up to) eight
    /// bit-packed booleans.
    /// </returns>

【讨论】:

【参考方案3】:

另一种 LINQ 方法,不如 @hfcs101 有效,但也很容易适用于其他值类型:

var a = new []  true, false, true, true, false, true ;
byte[] b = a.Select(BitConverter.GetBytes).SelectMany(x => x).ToArray();

【讨论】:

【参考方案4】:

您可以使用 LINQ。这不会是有效的,但会很简单。我假设您希望每个布尔值一个字节。

bool[] a = new bool[]  true, false, true, true, false, true ;
byte[] b = (from x in a select x ? (byte)0x1 : (byte)0x0).ToArray();

【讨论】:

在输入数组开始有数千个条目之前,我不会打赌这会特别低效。 这行不通。它将返回位数组。 (布尔数组)而不是字节。【参考方案5】:

看看BitConverter 类。根据您的需求的确切性质,它可能会非常巧妙地解决您的问题。

【讨论】:

【参考方案6】:

如果您对列表的类型有任何控制权,请尝试将其设为 List,然后它将在 ToArray() 上生成 byte[]。如果你有一个 ArrayList,你可以使用:

(byte[])list.ToArray(typeof(byte));

要获取列表,您可以使用未指定的列表迭代器创建一个作为构造函数的输入,然后生成 ToArray()?或者复制每个项目,从 bool 转换为一个新字节?

关于它是什么类型的列表的一些信息可能会有所帮助。

【讨论】:

False (-1) 为有符号字节返回 255。【参考方案7】:

这里有两种方法,具体取决于您是要将位打包成字节,还是与原始位一样多的字节:

    bool[] bools =  true, false, true, false, false, true, false, true,
                     true ;

    // basic - same count
    byte[] arr1 = Array.ConvertAll(bools, b => b ? (byte)1 : (byte)0);

    // pack (in this case, using the first bool as the lsb - if you want
    // the first bool as the msb, reverse things ;-p)
    int bytes = bools.Length / 8;
    if ((bools.Length % 8) != 0) bytes++;
    byte[] arr2 = new byte[bytes];
    int bitIndex = 0, byteIndex = 0;
    for (int i = 0; i < bools.Length; i++)
    
        if (bools[i])
        
            arr2[byteIndex] |= (byte)(((byte)1) << bitIndex);
        
        bitIndex++;
        if (bitIndex == 8)
        
            bitIndex = 0;
            byteIndex++;
        
    

【讨论】:

您可以通过以下方式一步计算字节数:int bytes = (bools.Length + 7) / 8; 使第二个增量行变得多余。也更快(与除法 + 模数相比只有一个除法) 很棒的方法 - 我会删除基本方法。这是浪费内存,byte 不是用来存储bit @fubo 虽然我同意你的观点,但这确实是一个意图问题:如果这是需要的,那么它就是需要的

以上是关于将 bool[] 转换为 byte[]的主要内容,如果未能解决你的问题,请参考以下文章

C#里面怎么把二进制转换成byte[]

Go -- 在Go语言中使用JSON struct

如何将 bool 转换为 BOOL?

如何将 NSNumber 转换和比较为 BOOL?

在C#中如何将byte[] 类型转换为图片类型

UnsupportedOperationException 将 byte[] 转换为 float[]