从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的下标读取相应的元素。我是否会错过其他方式?
答案 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
可能不适合该帐单。