当前位置: 首页 > 知识库问答 >
问题:

Swift位数组到字节数组(UInt8数组)

汤嘉平
2023-03-14

我有一个带位的数组:

var bits: [Bit]

如何将其转换为字节数组:

var bytes: [UInt8]

例如,我有280位,在字节数组中应该有35个UInt8。我可以想出一个解决方案,取8位,然后检查第一位是否为真,第二位是否为真,然后对结果求和,得出值。我会为我的bits数组中的每8位执行此操作。但我认为这是一个糟糕的解决方案(它可以工作,但需要进行不必要的计算)。我认为可能会有更快的解决方案与一些转移,所以,但我真的在这方面很差,所以我正在寻求帮助。谢谢

共有3个答案

康锦
2023-03-14

如果您更喜欢函数式方法,那么您可以使用reduce结合enumerate

后者,给定一个元素序列,创建一个(索引,元素)元组序列。我们需要索引来知道位的位置。

reduce用于将Bit数组缩减为UInt8

typealias IntegerType = UInt8

let initial = [IntegerType]()

let result = reduce(enumerate(bits), initial) { array, element in
    // The size in bits of a UInt8
    let size = sizeof(IntegerType) * 8

    // Create a mutable copy of the array returned at the previous iteration
    var next = array

    // If it's the first iteration, or an iteration divisible by the size of UInt8, 
    // append a new element to the array
    if element.index % size == 0 {
        next.append(0x00)
    }

    // Shift all bits of the last element to the left
    next[next.count - 1] <<= 1

    // If the current bit is one, add 1 to the rightmost bit
    // Using a logical OR
    if element.element == .One {
        next[next.count - 1] |= 0x01
    }

    return next
}

返回的结果是UInt8的数组。

Update忘记提到,如果要转换为其他整数类型,只需更改IntegerType别名即可。

池麒
2023-03-14

这是一个有趣的问题。我将此视为两个较小的问题:(1)如何将数组拆分为数组,其中每个较小的数组相当于一个字节的位;(2)如何将这些较小的数组转换为每个字节。

要解决第一个问题,我们可以编写一个函数,将数组分组为特定大小的片:

func group<T>(array: [T], byCount groupCount: Int) -> [Slice<T>] {
    // get a list of the start indices
    let startIndices = stride(from: 0, to: s.count, by: groupCount)
    // add `groupCount` to each to get the end indices
    let endIndices = lazy(startIndices).map { advance($0, groupCount, array.count) }

    // zip those together & map onto an array of slices of the input array
    return map(zip(startIndices, endIndices)) {
        array[$0.0 ..< $0.1]
    }
}

为了解决第二个问题,我们可以编写一个函数,将每个Slice

func bitsToByte(bits: Slice<Bit>) -> UInt8 {
    return bits.reduce(0) { accumulated, current in
        accumulated << 1 | (current == .One ? 1 : 0)
    }
}

最后,您可以依次调用其中的每一项,或将它们组合以获得结果:

// 1111 1111  1000 0000  0000 0001  0101 0101
let bits : [Bit] = [.One, .One, .One, .One, .One, .One, .One, .One,
    .One, .Zero,  .Zero, .Zero, .Zero, .Zero, .Zero, .Zero,
    .Zero,  .Zero, .Zero, .Zero, .Zero, .Zero, .Zero, .One,
    .Zero, .One, .Zero, .One, .Zero, .One, .Zero, .One]
let bytes = group(bits, byCount: 8).map(bitsToByte)
// [255, 128, 1, 85]

徐鑫鹏
2023-03-14

一种可能的解决方案是枚举数组中的所有位,并为所有“一”位设置UInt8数组中的相应位:

func bitsToBytes(bits: [Bit]) -> [UInt8] {
    let numBits = bits.count
    let numBytes = (numBits + 7)/8
    var bytes = [UInt8](count : numBytes, repeatedValue : 0)

    for (index, bit) in enumerate(bits) {
        if bit == .One {
            bytes[index / 8] += 1 << (7 - index % 8)
        }
    }

    return bytes
}

其主要思想是,对于位数组中给定的索引索引/8是字节数组中相应的索引,索引%8是字节中的位位置。您可以使用索引%87-索引%8作为移位量,具体取决于所需的位顺序。

例子:

// 0110 0100  0000 1001
let bits : [Bit] = [.Zero, .One, .One, .Zero,  .Zero, .One, .Zero, .Zero,  .Zero, .Zero, .Zero, .Zero,  .One, .Zero, .Zero, .One]
let bytes = bitsToBytes(bits)
println(bytes) // [100, 9]

或者,可以"内联"计算每组8比特。你必须检查哪种解决方案在你的情况下表现更好。

func bitsToBytes(bits: [Bit]) -> [UInt8] {
    let numBits = bits.count
    let numBytes = numBits/8
    var bytes = [UInt8](count : numBytes, repeatedValue : 0)
    for pos in 0 ..< numBytes {
        let val = 128 * bits[8 * pos].toIntMax() + 
            64 * bits[8 * pos + 1].toIntMax() +
            32 * bits[8 * pos + 2].toIntMax() +
            16 * bits[8 * pos + 3].toIntMax() +
            8 * bits[8 * pos + 4].toIntMax() +
            4 * bits[8 * pos + 5].toIntMax() +
            2 * bits[8 * pos + 6].toIntMax() +
            1 * bits[8 * pos + 7].toIntMax()
        bytes[pos] = UInt8(val)
    }
    return bytes
}

这里,为简单起见,如果比特数不是8的倍数,则忽略任何多余的比特。同样的代码也可以写得更“快速”一些

func bitsToBytes(bits: [Bit]) -> [UInt8] {
    return map(0 ..< bits.count/8) {
        pos in
        let val = 128 * bits[8 * pos].toIntMax() + 
            64 * bits[8 * pos + 1].toIntMax() +
            32 * bits[8 * pos + 2].toIntMax() +
            16 * bits[8 * pos + 3].toIntMax() +
            8 * bits[8 * pos + 4].toIntMax() +
            4 * bits[8 * pos + 5].toIntMax() +
            2 * bits[8 * pos + 6].toIntMax() +
            1 * bits[8 * pos + 7].toIntMax()
        return (UInt8(val))
    }
}

基准测试:这里现在是一个快速和肮脏的基准测试应用程序(代码如下),比较各种解决方案。它测量转换长度为256的10,000位数组的时间。测试是在苹果html" target="_blank">笔记本专业版2,3千兆赫英特尔酷睿i7上进行的,代码是用“发布”配置编译的。

Swift 1.1/Xcode 6.2(6C131e)的结果:

Martin1: 0.0460730195045471
Martin2: 0.0280380249023438
Martin3: 0.0374950170516968
Antonio: 5.85363000631332
Nate   : 4.86936402320862

Swift 1.2/Xcode 6.3(6D532l)的结果:

Martin1: 0.0228430032730103
Martin2: 0.00573796033859253
Martin3: 0.00732702016830444
Antonio: 0.515677988529205
Nate   : 0.634827971458435

代码:

protocol BitsToBytesConverter {
    var ident : String { get }
    func bitsToBytes(bits: [Bit]) -> [UInt8]
}

class MR1 : BitsToBytesConverter {

    let ident = "Martin1"
    func bitsToBytes(bits: [Bit]) -> [UInt8] {
        let numBits = bits.count
        let numBytes = (numBits + 7)/8
        var bytes = [UInt8](count : numBytes, repeatedValue : 0)

        for (index, bit) in enumerate(bits) {
            if bit == .One {
                bytes[index / 8] += UInt8(1 << (7 - index % 8))
            }
        }

        return bytes
    }
}

class MR2 : BitsToBytesConverter {

    let ident = "Martin2"

    func bitsToBytes(bits: [Bit]) -> [UInt8] {
        let numBits = bits.count
        let numBytes = numBits/8
        var bytes = [UInt8](count : numBytes, repeatedValue : 0)
        for pos in 0 ..< numBytes {
            let val = 128 * bits[8 * pos].toIntMax() + 
                64 * bits[8 * pos + 1].toIntMax() +
                32 * bits[8 * pos + 2].toIntMax() +
                16 * bits[8 * pos + 3].toIntMax() +
                8 * bits[8 * pos + 4].toIntMax() +
                4 * bits[8 * pos + 5].toIntMax() +
                2 * bits[8 * pos + 6].toIntMax() +
                1 * bits[8 * pos + 7].toIntMax()
            bytes[pos] = UInt8(val)
        }
        return bytes
    }
}

class MR3 : BitsToBytesConverter {

    let ident = "Martin3"

    func bitsToBytes(bits: [Bit]) -> [UInt8] {
        return map(0 ..< bits.count/8) {
            pos in
            let val = 128 * bits[8 * pos].toIntMax() + 
                64 * bits[8 * pos + 1].toIntMax() +
                32 * bits[8 * pos + 2].toIntMax() +
                16 * bits[8 * pos + 3].toIntMax() +
                8 * bits[8 * pos + 4].toIntMax() +
                4 * bits[8 * pos + 5].toIntMax() +
                2 * bits[8 * pos + 6].toIntMax() +
                1 * bits[8 * pos + 7].toIntMax()
            return (UInt8(val))
        }
    }
}

class AB : BitsToBytesConverter {

    let ident = "Antonio"

    typealias IntegerType = UInt8

    func bitsToBytes(bits: [Bit]) -> [UInt8] {

        let initial = [IntegerType]()

        return reduce(enumerate(bits), initial) { array, element in
            // The size in bits of a UInt8
            let size = sizeof(IntegerType) * 8

            // Create a mutable copy of the array returned at the previous iteration
            var next = array

            // If it's the first iteration, or an iteration divisible by the size of UInt8, 
            // append a new element to the array
            if element.index % size == 0 {
                next.append(0x00)
            }

            // Shift all bits of the last element to the left
            next[next.count - 1] <<= 1

            // If the current bit is one, add 1 to the rightmost bit
            // Using a logical OR
            if element.element == .One {
                next[next.count - 1] |= 0x01
            }

            return next
        }
    }
}

class NC : BitsToBytesConverter {

    let ident = "Nate   "

    func group<T>(array: [T], byCount groupCount: Int) -> [Slice<T>] {
        // get a list of the start indices
        let startIndices = stride(from: 0, to: array.count, by: groupCount)
        // add `groupCount` to each to get the end indices
        let endIndices = lazy(startIndices).map { advance($0, groupCount, array.count) }

        // zip those together & map onto an array of slices of the input array
        return map(Zip2(startIndices, endIndices)) {
            array[$0.0 ..< $0.1]
        }
    }

    func bitsToByte(bits: Slice<Bit>) -> UInt8 {
        return bits.reduce(0) { accumulated, current in
            accumulated << 1 | (current == .One ? 1 : 0)
        }
    }

    func bitsToBytes(bits: [Bit]) -> [UInt8] {
        return group(bits, byCount: 8).map(bitsToByte)
    }
}


let numBits = 256 // Bits per bit array
let numBitArrays = 10000 // Number of bit arrays

func randomBits() -> [Bit] {
    return map(0 ..< numBits) { _  in
        Bit(rawValue: Int(arc4random_uniform(2)))!
    }
}

func randomBitsArray() -> [[Bit]] {
    return map(0 ..< numBitArrays) { _ in
        randomBits()
    }
}

let bitsArray = randomBitsArray()

func test(conv : BitsToBytesConverter) {
    let x = conv.bitsToBytes([])
    let startTime = NSDate()
    for bits in bitsArray {
        let bytes = conv.bitsToBytes(bits)
    }
    let duration = -startTime.timeIntervalSinceNow
    println("\(conv.ident): \(duration)")
}

test(MR1())
test(MR2())
test(MR3())
test(AB())
test(NC())
 类似资料:
  • 问题内容: 我试图理解一个到字符串,一个的字符串表示形式到转换…我将我的转换成一个要发送的字符串,然后我希望我的Web服务(用python编写)将数据直接回显给客户端。 当我从Java应用程序发送数据时… 字节发送.. 发送(这是Arrays.toString()的结果,它应该是我的字节数据的字符串表示形式,该数据将通过电线发送): 在python端,python服务器将字符串返回给调用方(我可以

  • 问题内容: 我在将Byte数组快速转换为字符串时遇到问题。我搜索并找到一个简单的解决方案 但是显示错误没有成员。谁能建议我解决方案? 这是我要获取的代码,并将其转换为字节数组,然后我必须将该字节数组转换为字符串。 问题答案: Swift 3 / Xcode 8 更新 : 来自的字符串: 来自的字符串: Swift 2 / Xcode 7 更新 : 来自的字符串: 来自的字符串: 先前的答案: 没有

  • 如何在java中将字节数组转换为int。我正在构建蓝牙应用程序,我在其上收到字节数组中的消息,然后将其转换为字符串,它已成功转换,但我也希望它以整数形式存在

  • 问题内容: 使用Swift,我想将字节从uint8_t数组转换为整数。 “ C”示例: 快速尝试: 从Swift中的UInt8数组创建UInt16值的正确语法或代码是什么? 我对NSData版本感兴趣,并且正在寻找不使用临时数组的解决方案。 问题答案: 如果您想通过,它将像这样工作: 或者: 两种变体都假定字节按主机字节顺序排列。 Swift 3(Xcode 8)更新:

  • 问题内容: 我的成员有一个结构,我正在用编写它。麻烦的是,它将s解释为s,并且它输出字符串而不是数字数组。 如果它是,我可以使它工作,但是如果可以避免的话,我不想分配和复制这些项目。我可以吗? 问题答案: 根据文档,a 将被编码为Base64字符串。 “数组和切片值编码为JSON数组, 除了[] byte编码为base64编码的字符串 ,而nil slice编码为空JSON对象。” 因此,我认为您

  • 比方说,我有一个字节数组,包含没有标题的原始位图数据。 但是位图数据有点奇怪,我不太确定,但是如果宽度是NPOT(不是二次方),位图数据似乎没有正确对齐 我使用以下代码从此类位图数据构造bmp: 到目前为止,代码运行良好。但由于某些原因,我需要实现“导入位图”,这意味着我需要从位图实例中获取“奇怪”的位图数据。 我该怎么做?

  • 问题内容: 我正在尝试 从字节数组创建一个。 在Obj-C中,我可能这样做: 我无法弄清楚Swift中的等效功能。 问题答案: 有一个带有指针的初始化程序:。一个参数可以接受多种不同的东西,包括一个简单的斯威夫特阵列,所以你可以使用几乎相同的语法在Objective-C。传递数组时,需要确保将其标识为数组,否则Swift的类型推断将假定您要创建一个数组。 您可以在Apple的与C API交互的 文

  • 问题内容: 我得到一个整数: 当我使用方法: 给出: 但我想要一个字节数组: 我该怎么做? 问题答案: 使用Java NIO的ByteBuffer非常简单: 输出: