【问题标题】:How to factor an integer into an array of powers of 2?如何将整数分解为 2 的幂数组?
【发布时间】:2018-08-30 13:47:11
【问题描述】:

我正在尝试实现类似二进制掩码之类的东西,其中我将 Int 转换为它的组件数组(2 的幂),例如:

69 = [64, 4, 1]

我不想使用二进制掩码和移位,因为我想对界面元素使用 Swift 枚举:

enum State: Int{
    case readyButton = 1
    case workingButton = 2
    case sleepingButton = 4
   //etc
}

then 7 = [.sleepingButton, .workingButton, .readyButton] // 7 = 4+2+1

在 Swift 中是否有一些工具可以帮助我将 Int 转换为 2 个组件的幂?

【问题讨论】:

  • 听起来像是OptionSet 的工作? developer.apple.com/documentation/swift/optionset
  • 谢谢,有没有办法将原始 Int 分解为 OptionSet 值数组?
  • @AlexStone:您可以“枚举” OptionSet 值的位:stackoverflow.com/q/32102936/1187415
  • swift中没有bit to bit的操作符吗?
  • @AlexStone 唯一的状态是let rawValue: Int。只需使用init(rawValue: Int) 从整数中获取集合,然后使用.contains(.readyButton)

标签: arrays swift math


【解决方案1】:

您可能正在寻找类似的东西。正如它所写的那样,当值不匹配时它会崩溃,但您可以根据您的目的对其进行调整。虽然它确实使用了移位,但它仍然可以很好地转换为您的枚举。

extension UInt32 {
    func state() -> [State] {
        var bitvals: [UInt32] = []
        var mask: UInt32 = 1
        while mask > 0 {
            if mask & self > 0 {
                bitvals.append(mask)
            }
            mask = mask << 1
        }
        let state = bitvals.map { State(rawValue: $0)! }
        return state
    }
}
enum State: UInt32 {
    case readyButton = 1
    case workingButton = 2
    case sleepingButton = 4
}

let val: UInt32 = 7
print(val.state())

这将打印出您在问题末尾给出的示例。

【讨论】:

  • 你可以在索引 0 处插入你的元素而不是追加它
【解决方案2】:

更新了将任何 Int 转换为 2 的幂的数组的答案。如果您希望它在负值上崩溃,请取消注释致命错误

enum State: Int {
    case illegal = -1
    case readyButton = 1
    case workingButton = 2
    case sleepingButton = 4
}

这是将整数分解为 2 的幂的通用解决方案:

extension Int {

    func toPowersOf2() -> [Int] {
        guard self > 0 else {
//            fatalError("The number should be strictly positive")
            print("The number should be strictly positive")
            return [-1] //not really - use fatal error above to enforce crash if you don't want this behavior
        }
        var arrayOfPowers: [Int] = [] //Will hold the desired powers
        var remainder: Int = self   //We will substract found powers from the original number

        //Since Ints are coded on 64 bits (the 64th is for the sign)
        //Let's create an array of all the powers of 2 that
        //could be used to decompose an integer
        let powers = (0...62).map { NSDecimalNumber(decimal: pow(2.0, $0)).intValue }

        //Let's go from the highest to the lowest power
        for i in (0 ..< powers.count).reversed() {
            //Here we are looking for the power just smaller than the remainder
            if i < powers.count - 1, powers[i] <= remainder, powers[i + 1] > remainder {
                let p = powers[i]
                arrayOfPowers.append(p)
                remainder -= p
            }

                //if this is the biggest power and it is smaller than the number, then add it to arrayOfPowers
            else if i == powers.count - 1, powers[i] <= remainder {
                let p = powers[i]
                arrayOfPowers.append(p)
            }
        }
        return arrayOfPowers
    }

    func toStateArray() -> [State] {
        let array = self.toPowersOf2().map{ State(rawValue: $0) }.filter{ $0 != nil }
        return array as! [State]
    }
}

你可以这样使用它:

(-1).toStateArray()//[illegal]
0.toStateArray()   //[illegal]
7.toPowersOf2()    //[4, 2, 1]
7.toStateArray()   //[sleepingButton, workingButton, readyButton]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 2016-05-05
    • 2017-02-03
    • 1970-01-01
    • 1970-01-01
    • 2015-03-09
    相关资源
    最近更新 更多