如何从Swift中的集合中获取随机元素?

cou*_*elk 12 set swift

从Swift 1.2(目前可用作测试版)开始,Apple推出了Set集合类型.

说,我有一套像:

var set = Set<Int>(arrayLiteral: 1, 2, 3, 4, 5)
Run Code Online (Sandbox Code Playgroud)

现在我想得到一个随机元素.问题是怎么样的? Set没有提供subscript(Int)Array.相反,它有subscript(SetIndex<T>).但首先,SetIndex<T>没有可访问的初始值设定项(因此,我不能只创建一个带有我需要的偏移量的索引),其次,即使我可以获取set(var startIndex = set.startIndex)中第一个元素的索引,那么我可以得到的唯一方法到第N个索引是通过连续调用successor().

因此,我现在只能看到2个选项,既丑陋又昂贵:

  • 将集合转换为array(var array = [Int](set))并使用其下标(完全接受Int); 要么
  • 获取集合中第一个元素的索引,遍历successor()方法链以获取第N个索引,然后通过set的下标读取相应的元素.

我还想念别的吗?

Cœu*_*œur 10

从Swift 4.2开始,您可以使用randomElement:

let random = set.randomElement()
Run Code Online (Sandbox Code Playgroud)


Rob*_*ier 8

也许最好的办法是advance根据指导successor为您提供:

func randomElementIndex<T>(s: Set<T>) -> T {
    let n = Int(arc4random_uniform(UInt32(s.count)))
    let i = advance(s.startIndex, n)
    return s[i]
}
Run Code Online (Sandbox Code Playgroud)

(编辑:嘿;注意到你实际上更新了问题以包含这个答案,然后我将它添加到我的答案中...好吧,仍然是一个好主意,我也学到了一些东西.:D)

你也可以走这套而不是指数(这是我的第一个想法,但后来我记得advance).

func randomElement<T>(s: Set<T>) -> T {
    let n = Int(arc4random_uniform(UInt32(s.count)))
    for (i, e) in enumerate(s) {
        if i == n { return e }
    }
    fatalError("The above loop must succeed")
}
Run Code Online (Sandbox Code Playgroud)

  • Justin Lewis所有改变的是你现在必须在索引`扩展名set {func randomElement() - > Element {let n = Int(arc4random_uniform(UInt32(count)))上调用`advancedBy(_ :)`; let i = startIndex.advancedBy(n); return self [i];}}` (2认同)

ars*_*ius 5

在快速3

extension Set {
    public func randomObject() -> Element? {
        let n = Int(arc4random_uniform(UInt32(self.count)))
        let index = self.index(self.startIndex, offsetBy: n)
        return self.count > 0 ? self[index] : nil
    }
}
Run Code Online (Sandbox Code Playgroud)