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

时间:2015-02-12 23:27:55

标签: swift set

从Swift 1.2开始,Apple引入了Set集合类型。

说,我有一套像:

var set = Set<Int>(arrayLiteral: 1, 2, 3, 4, 5)

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

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

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

我是否会错过其他方式?

6 个答案:

答案 0 :(得分:9)

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

let random = set.randomElement()

答案 1 :(得分: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]
}

(编辑:嘿;注意到你实际上更新了问题以包含这个答案,然后我将它添加到我的答案中......好吧,还是一个好主意,我也学到了一些东西。: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")
}

答案 2 :(得分:5)

在swift 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
    }
}

答案 3 :(得分:4)

extension Set {
    func randomElement() -> Element? {
        return count == 0 ? nil : self[advance(self.startIndex, Int(arc4random()) % count)]
    }
}

答案 4 :(得分:2)

根据以上评论重新进行Swift更新,对Set的扩展使用了一个小改动:

func randomElement() -> Element?
{
    let randomInt = Int(arc4random_uniform(UInt32(self.count)))
    let index = startIndex.advancedBy(randomInt)
    return count == 0 ? nil: self[index]
}

答案 5 :(得分:1)

如果你想要Set中的'随机'元素,那么你可以使用:

/// A member of the set, or `nil` if the set is empty.
var first: T? { get }

获取第0个索引或第1,000,000个索引没有区别 - 它们都是任意对象。

但是,如果您想要重复调用每次都会返回一个可能不同的元素,那么first可能不适合该帐单。