Как разложить целое число в массив степеней 2? - PullRequest
0 голосов
/ 30 августа 2018

Я пытаюсь реализовать что-то вроде бинарной маскировки, где я превращаю 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 ]

0 голосов
/ 30 августа 2018

Обновлен ответ для преобразования любого 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]
0 голосов
/ 30 августа 2018

Возможно, вы ищете что-то подобное. Как написано, произойдет сбой, когда значения не совпадают, но вы можете адаптировать его для своих целей. Хотя он использует сдвиг, он все равно прекрасно конвертируется в ваше перечисление.

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())

Это распечатало бы пример, который вы дали в конце вашего вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...