将OptionSetType映射到Array

Dan*_* T. 2 swift

鉴于以下内容:

struct Weekdays: OptionSetType {

    let rawValue: Int
    init(rawValue: Int) { self.rawValue = rawValue }

    static let Monday = Weekdays(rawValue: 1)
    static let Tuesday = Weekdays(rawValue: 2)
    static let Wednesday = Weekdays(rawValue: 4)
    static let Thursday = Weekdays(rawValue: 8)

    static let allOptions: [Weekdays] = [.Monday, .Tuesday, .Wednesday, .Thursday]

}
Run Code Online (Sandbox Code Playgroud)

我可以通过这样做将数组Ints转换为Weekdays对象:

let arr = [1, 4]
let weekdays = arr.reduce(Weekdays()) { $0.union(Weekdays(rawValue: $1)) }
Run Code Online (Sandbox Code Playgroud)

我的问题是,如何获取一个Weekdays对象并将其转换为一个数组Ints

Mar*_*n R 8

(不一定更好,但以不同的方式来看待它并稍微更一般).

OptionSetType继承自RawRepresentable,因此可以转换为关联的原始类型,在您的情况下是 Int.

因此,"缺失链接"是原始值(例如5)和按位分量(例如[1, 4])的整数数组之间的转换.

这可以通过Int扩展方法完成:

extension Int {
    init(bitComponents : [Int]) {
        self = bitComponents.reduce(0, combine: (+))
    }

    func bitComponents() -> [Int] {
        return (0 ..< 8*sizeof(Int)).map( { 1 << $0 }).filter( { self & $0 != 0 } )
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你从数组到Weekdays对象的转换成为

let arr : [Int] = [1, 4]
let weekdays = Weekdays(rawValue: Int(bitComponents: arr))
print(weekdays)
// app.Weekdays(rawValue: 5)
Run Code Online (Sandbox Code Playgroud)

和反向转换

let array = weekdays.rawValue.bitComponents()
print(array)
// [1, 4]
Run Code Online (Sandbox Code Playgroud)

好处:

  • allOptions:不需要明确的定义.
  • 它可以应用于其他选项集类型(具有Int 原始值).

也可以尝试将转换定义为协议扩展,例如IntegerType,也可以将其与其他整数原始类型一起使用.然而,这似乎有点复杂/丑陋,因为左移操作符<<不是 IntegerType(或任何)协议的一部分.


Swift 3更新:

extension Int {
    init(bitComponents : [Int]) {
        self = bitComponents.reduce(0, +)
    }

    func bitComponents() -> [Int] {
        return (0 ..< 8*MemoryLayout<Int>.size).map( { 1 << $0 }).filter( { self & $0 != 0 } )
    }
}
Run Code Online (Sandbox Code Playgroud)