As of Swift 1.2, Apple introduces Set
collection type.
Say, I have a set like:
var set = Set(arrayLiteral: 1, 2, 3, 4, 5)
extension Set {
func randomElement() -> Element? {
return count == 0 ? nil : self[advance(self.startIndex, Int(arc4random()) % count)]
}
}
If you want a 'random' element from a Set
then you use:
/// A member of the set, or `nil` if the set is empty.
var first: T? { get }
Get the 0th index or the 1,000,000th index makes no difference - they are all an arbitrary object.
But, if you want repeated calls to return a likely different element each time, then first
might not fit the bill.
Probably the best approach is advance
which walks successor
for you:
func randomElementIndex<T>(s: Set<T>) -> T {
let n = Int(arc4random_uniform(UInt32(s.count)))
let i = advance(s.startIndex, n)
return s[i]
}
(EDIT: Heh; noticed you actually updated the question to include this answer before I added it to my answer... well, still a good idea and I learned something too. :D)
You can also walk the set rather than the indices (this was my first thought, but then I remembered 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")
}
In 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
}
}
As per comments above re Swift updates, used a minor change for an extension to Set:
func randomElement() -> Element?
{
let randomInt = Int(arc4random_uniform(UInt32(self.count)))
let index = startIndex.advancedBy(randomInt)
return count == 0 ? nil: self[index]
}
Starting with Swift 4.2, you can use randomElement:
let random = set.randomElement()