Swift:选择一个随机枚举值

时间:2014-10-08 15:42:07

标签: random swift enums

我正在尝试随机选择一个枚举值,这是我目前的尝试:

enum GeometryClassification {

    case Circle
    case Square
    case Triangle
    case GeometryClassificationMax

}

和随机选择:

let shapeGeometry = ( arc4random() % GeometryClassification.GeometryClassificationMax ) as GeometryClassification
然而,这却失败了。

我得到的错误如下:

'GeometryClassification' is not convertible to 'UInt32'

关于如何解决这个问题的任何想法?

9 个答案:

答案 0 :(得分:29)

自从撰写提供更好解决方案的答案后,Swift获得了新功能 - 请参阅this answer


我对你的最后一个案例并不感到疯狂 - 似乎你只是将.GeometryClassificationMax包括在内以便启用随机选择。在使用switch语句的任何地方,您都需要考虑该额外情况,并且它没有语义值。相反,enum上的静态方法可以确定最大值并返回随机情况,并且更容易理解和维护。

enum GeometryClassification: UInt32 {
    case Circle
    case Square
    case Triangle

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

    static func randomGeometry() -> GeometryClassification {
        // pick and return a new value
        let rand = arc4random_uniform(_count)
        return GeometryClassification(rawValue: rand)!
    }
}

您现在可以在enum声明中耗尽switch

switch GeometryClassification.randomGeometry() {
case .Circle:
    println("Circle")
case .Square:
    println("Square")
case .Triangle:
    println("Triangle")
}

答案 1 :(得分:8)

因为你在enum类中,所以使用random()方法显式引用最高值将不必每次都计算它们:

enum GeometryClassification: UInt32 {
    case Circle
    case Square
    case Triangle

    static func random() -> GeometryClassification {
        // Update as new enumerations are added
        let maxValue = Triangle.rawValue

        let rand = arc4random_uniform(maxValue+1)
        return GeometryClassification(rawValue: rand)!
    }
}

答案 2 :(得分:8)

在Swift中,实际上有一个名为CaseIterable的枚举协议,如果将其添加到枚举中,则可以使用.allCases将所有案例作为集合引用,如下所示:

enum GeometryClassification: CaseIterable {

    case Circle
    case Square
    case Triangle

}

然后您可以依次.allCases.randomElement()来获得一个随机的

let randomGeometry = GeometryClassification.allCases.randomElement()!

需要强制展开,因为有可能枚举没有大小写,因此randomElement()将返回nil

答案 3 :(得分:6)

对于Swift 5,有“ RandomNumberGenerator”:

<div class="header_library">
    <div class="row">
      <p>Выберите плейлист или несколько и нажмите кнопку</p>
      <div style="margin: 10px;">
       <input id="btn_transfer_checkbox" type="button" value="Перенести">
     </div>
    </div>
    <div class="row">
      <input id="btn_checked_all" type="button" value="Выбрать все">
    </div>
</div>
<div>
    Some elements
</div>

答案 4 :(得分:5)

您需要为枚举分配原始类型。如果使用整数类型,则枚举大小写值将从0开始自动生成:

enum GeometryClassification: UInt32 {  
    case Circle
    case Square
    case Triangle
    case GeometryClassificationMax
}

&#34;与C和Objective-C不同,Swift枚举成员在创建时不会被赋予默认的整数值。&#34; - 根据this页面。指定整数类型可以让它知道以通常的方式生成值。

然后你可以像这样生成随机值:

let randomEnum: GeometryClassification = GeometryClassification.fromRaw(arc4random_uniform(GeometryClassification.GeometryClassificationMax.toRaw()))!

这是一个非常丑陋的电话,而且所有那些来自“Raw&#39;并且&#39; toRaw&#39;调用是相当不优雅的,所以我真的建议先生成一个你想要的范围内的随机UInt32,然后从该值创建一个GeometryClassification:

GeometryClassification.fromRaw(someRandomUInt32)

答案 5 :(得分:1)

这是我的Swift 1.2拍摄:

enum GeometryClassification : Int {
    case Circle = 0
    case Square = 1
    case Triangle = 2

    static func random() -> GeometryClassification {
        let min = MutationType.Circle.rawValue
        let max = MutationType.Triangle.rawValue
        let rand = Int.random(min: min, max: max) // Uses ExSwift!
        return self(rawValue: rand)!
    }
}

答案 6 :(得分:1)

您可以将所有值放入数组并生成随机,

extension GeometryClassification {

    static func random() -> GeometryClassification {
        let all: [GeometryClassification] = [.Circle,
                                             .Square,
                                             .Triangle,
                                             .GeometryClassificationMax]
        let randomIndex = Int(arc4random()) % all.count
        return all[randomIndex]
    }
}

答案 7 :(得分:0)

我使用 Andy's 答案编写了一个全局扩展。享受:)

extension CaseIterable {
    static func random<G: RandomNumberGenerator>(using generator: inout G) -> Self.AllCases.Element {
        return Self.allCases.randomElement(using: &generator)!
    }

    static func random() -> Self.AllCases.Element {
        var g = SystemRandomNumberGenerator()
        return Self.random(using: &g)
    }
}

只需扩展您的枚举以符合 CaseIterable 协议并使用类似:

let state = YourEnum.random()

答案 8 :(得分:0)

最简单的方法是创建一个全局扩展:

extension CaseIterable {
    static func randomElement() -> AllCases.Element {
        guard Self.allCases.count > 0 else {
            fatalError("There must be at least one case in the enum")
        }
        return Self.allCases.randomElement()!
    }
}

这样任何符合 CaseIterable 的枚举都会自动具有该功能