从枚举的子部分中选择随机值

时间:2017-03-31 16:01:59

标签: swift enums

给出一个Swift枚举:

enum PerformerPosition: Int {

    case String_Violin1
    case String_Violin2
    case String_Viola
    case String_Cello
    case String_CB

    case Wind_Oboe
    case Wind_Clarinet
    case Wind_Flute
    ...

}

(对于项目的需要,我能够拥有嵌套枚举。)我想只选择带String_前缀的枚举值。

到目前为止,我所知道的唯一方法是从所有可用案例中做一个随机枚举值,如下:

private static let _count: PerformerPosition.RawValue = {
    // find the maximum enum value
    var maxValue: Int = 0
    while let _ = PerformerPosition(rawValue: maxValue) { 
        maxValue += 1
    }
    return maxValue
}()

static func randomPerformer() -> PerformerPosition {
    // pick and return a new value
    let rand = arc4random_uniform(UInt32(count))
    return PlayerPosition(rawValue: Int(rand))!
}

我怎么能这样做,所以我能够选择一个基于String_前缀的随机值,而不得不求助于硬编码一个较高的值(例如,new可以添加String_前缀位置)?感谢

3 个答案:

答案 0 :(得分:2)

即使添加了新位置,您也不想更改任何代码。正确?

为此,您需要动态获取所有枚举案例,而不是对其进行硬编码。根据{{​​3}},您可以使用此方法来获取所有案例:

protocol EnumCollection : Hashable {}
extension EnumCollection {
    static func cases() -> AnySequence<Self> {
        typealias S = Self
        return AnySequence { () -> AnyIterator<S> in
            var raw = 0
            return AnyIterator {
                let current : Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee } }
                guard current.hashValue == raw else { return nil }
                raw += 1
                return current
            }
        }
    }
}

获得此cases方法后,您可以轻松获得所需内容:

let startingWithString = Array(PerformerPosition.cases().filter { "\($0)".hasPrefix("String_") })
let rand = arc4random_uniform(UInt32(startingWithString.count))
let randomPosition = startingWithString[Int(rand)]

答案 1 :(得分:1)

如果您的枚举中有不同的子集,并且您需要单独访问它们,我建议以某种方式识别子集,请考虑:

enum PerformerPosition: Int {

    case String_Violin1
    case String_Violin2
    case String_Viola
    case String_Cello
    case String_CB

    case Wind_Oboe
    case Wind_Clarinet
    case Wind_Flute

    static let strings: [PerformerPosition] = [
        .String_Violin1, .String_Violin2, .String_Viola, .String_Cello, .String_CB
    ]

    static let winds: [PerformerPosition] = [
        .Wind_Oboe, .Wind_Clarinet, .String_Viola, .Wind_Flute
    ]
}

请注意,这将为您提供以下几点:

  1. 您不需要String_Wind_前缀。您只需使用.violin1.oboe

  2. 即可
  3. 您只需从数组中生成随机位置

  4. 即可
  5. 您可以直接查看您的职位类型:

    let isString = PerformerPosition.strings.contains(.violin1)
    

答案 2 :(得分:0)

我在PlayGround中制作了这个:

func randomPerformer() -> PerformerPosition {
    // pick and return a new value
    let rand = arc4random_uniform(_count)
    let string = String(describing:PerformerPosition(rawValue: rand))
    if(string.contains("String_")){
            return PerformerPosition(rawValue: rand)!
    }else{
            return randomPerformer()
    }
}