January 31, 2018 · Ralf Ebert » iOS Developer Blog »

Getting random elements from a Swift array

There are helpful APIs in GameplayKit for Randomization, including one to shuffle arrays. Unfortunately it’s for NSArray and doesn’t support Swift Generics. Therefore I recommend the following extension to simplify getting random elements from a Swift array (or any Swift collection like a Range or Set):

let range = 1...49
print("single random element: ", range.sample!)
print("multiple random elements: ", range.sample(6))

let names = ["Alice", "Bob", "Carol", "Dave", "Eve", "Frank", "Grace", "Heidi"]
print("single random element: ", names.sample!)
print("multiple random elements: ", names.sample(3))
print("array in random order: ", names.shuffled)

let set = Set(names)
print("single random element: ", set.sample!)
print("multiple random elements: ", set.sample(3))

Array+Sample.swift:

// Copyright 2018, Ralf Ebert
// Source    https://www.ralfebert.de/ios-examples/swift/array-random-sample/
// License   https://opensource.org/licenses/MIT
// License   https://creativecommons.org/publicdomain/zero/1.0/

import Darwin

extension Collection {
    
    /**
     * Returns a random element of the Array or nil if the Array is empty.
     */
    var sample : Element? {
        guard !isEmpty else { return nil }
        let offset = arc4random_uniform(numericCast(self.count))
        let idx = self.index(self.startIndex, offsetBy: numericCast(offset))
        return self[idx]
    }

    /**
     * Returns `count` random elements from the array.
     * If there are not enough elements in the Array, a smaller Array is returned.
     * Elements will not be returned twice except when there are duplicate elements in the original Array.
     */
    func sample(_ count : UInt) -> [Element] {
        let sampleCount = Swift.min(numericCast(count), self.count)

        var elements = Array(self)
        var samples : [Element] = []
        
        while samples.count < sampleCount {
            let idx = (0..<elements.count).sample!
            samples.append(elements.remove(at: idx))
        }
        
        return samples
    }

}

extension Array {
    
    /**
     * Shuffles the elements in the Array in-place using the
     * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle).
     */
    mutating func shuffle() {
        guard self.count >= 1 else { return }

        for i in (1..<self.count).reversed() {
            let j = (0...i).sample!
            self.swapAt(j, i)
        }
    }
    
    /**
      * Returns a new Array with the elements in random order.
      */
    var shuffled : [Element] {
        var elements = self
        elements.shuffle()
        return elements
    }
    
}
Btn read 3c0e607615 iOS Developer Blog
Btn subscribe 930758687e Subscribe: Email · Twitter
Btn training bbbdf557d2 Next iOS training: 25. Februar - 01. März 2019, Stuttgart
Btn about 5378472193 About me · Contact