Pick a random element from an array

ArraysSwiftRandom

Arrays Problem Overview


Suppose I have an array and I want to pick one element at random.

What would be the simplest way to do this?

The obvious way would be array[random index]. But perhaps there is something like ruby's array.sample? Or if not could such a method be created by using an extension?

Arrays Solutions


Solution 1 - Arrays

Swift 4.2 and above

The new recommended approach is a built-in method on the Collection protocol: randomElement(). It returns an optional to avoid the empty case I assumed against previously.

let array = ["Frodo", "Sam", "Wise", "Gamgee"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0

If you don't create the array and aren't guaranteed count > 0, you should do something like:

if let randomElement = array.randomElement() { 
    print(randomElement)
}

Swift 4.1 and below

Just to answer your question, you can do this to achieve random array selection:

let array = ["Frodo", "sam", "wise", "gamgee"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])

The castings are ugly, but I believe they're required unless someone else has another way.

Solution 2 - Arrays

Riffing on what Lucas said, you could create an extension to the Array class like this:

extension Array {
    func randomItem() -> Element? {
        if isEmpty { return nil }
	    let index = Int(arc4random_uniform(UInt32(self.count)))
	    return self[index]
    }
}

For example:

let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16]
let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>

Solution 3 - Arrays

Swift 4 version:

extension Collection where Index == Int {

    /**
     Picks a random element of the collection.

     - returns: A random element of the collection.
     */
    func randomElement() -> Iterator.Element? {
        return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
    }
    
}

Solution 4 - Arrays

In Swift 2.2 this can be generalised so that we have:

UInt.random
UInt8.random
UInt16.random
UInt32.random
UInt64.random
UIntMax.random

// closed intervals:

(-3...3).random
(Int.min...Int.max).random

// and collections, which return optionals since they can be empty:

(1..<4).sample
[1,2,3].sample
"abc".characters.sample
["a": 1, "b": 2, "c": 3].sample

First, implementing static random property for UnsignedIntegerTypes:

import Darwin

func sizeof <T> (_: () -> T) -> Int { // sizeof return type without calling
	return sizeof(T.self)
}

let ARC4Foot: Int = sizeof(arc4random)

extension UnsignedIntegerType {
    static var max: Self { // sadly `max` is not required by the protocol
	    return ~0
    }
	static var random: Self {
		let foot = sizeof(Self)
		guard foot > ARC4Foot else {
			return numericCast(arc4random() & numericCast(max))
		}
		var r = UIntMax(arc4random())
		for i in 1..<(foot / ARC4Foot) {
			r |= UIntMax(arc4random()) << UIntMax(8 * ARC4Foot * i)
		}
		return numericCast(r)
	}
}

Then, for ClosedIntervals with UnsignedIntegerType bounds:

extension ClosedInterval where Bound : UnsignedIntegerType {
	var random: Bound {
		guard start > 0 || end < Bound.max else { return Bound.random }
		return start + (Bound.random % (end - start + 1))
	}
}

Then (a little more involved), for ClosedIntervals with SignedIntegerType bounds (using helper methods described further below):

extension ClosedInterval where Bound : SignedIntegerType {
	var random: Bound {
		let foot = sizeof(Bound)
		let distance = start.unsignedDistanceTo(end)
		guard foot > 4 else { // optimisation: use UInt32.random if sufficient
			let off: UInt32
			if distance < numericCast(UInt32.max) {
				off = UInt32.random % numericCast(distance + 1)
			} else {
				off = UInt32.random
			}
			return numericCast(start.toIntMax() + numericCast(off))
		}
		guard distance < UIntMax.max else {
			return numericCast(IntMax(bitPattern: UIntMax.random))
		}
		let off = UIntMax.random % (distance + 1)
		let x = (off + start.unsignedDistanceFromMin).plusMinIntMax
		return numericCast(x)
	}
}

... where unsignedDistanceTo, unsignedDistanceFromMin and plusMinIntMax helper methods can be implemented as follows:

extension SignedIntegerType {
	func unsignedDistanceTo(other: Self) -> UIntMax {
		let _self = self.toIntMax()
		let other = other.toIntMax()
		let (start, end) = _self < other ? (_self, other) : (other, _self)
		if start == IntMax.min && end == IntMax.max {
			return UIntMax.max
		}
		if start < 0 && end >= 0 {
			let s = start == IntMax.min ? UIntMax(Int.max) + 1 : UIntMax(-start)
			return s + UIntMax(end)
		}
		return UIntMax(end - start)
	}
	var unsignedDistanceFromMin: UIntMax {
		return IntMax.min.unsignedDistanceTo(self.toIntMax())
	}
}

extension UIntMax {
	var plusMinIntMax: IntMax {
		if self > UIntMax(IntMax.max) { return IntMax(self - UIntMax(IntMax.max) - 1) }
		else { return IntMax.min + IntMax(self) }
	}
}

Finally, for all collections where Index.Distance == Int:

extension CollectionType where Index.Distance == Int {
	var sample: Generator.Element? {
		if isEmpty { return nil }
		let end = UInt(count) - 1
		let add = (0...end).random
		let idx = startIndex.advancedBy(Int(add))
		return self[idx]
	}
}

... which can be optimised a little for integer Ranges:

extension Range where Element : SignedIntegerType {
	var sample: Element? {
		guard startIndex < endIndex else { return nil }
		let i: ClosedInterval = startIndex...endIndex.predecessor()
		return i.random
	}
}

extension Range where Element : UnsignedIntegerType {
	var sample: Element? {
		guard startIndex < endIndex else { return nil }
		let i: ClosedInterval = startIndex...endIndex.predecessor()
		return i.random
	}
}

Solution 5 - Arrays

You can use Swift's built-in random() function as well for the extension:

extension Array {
    func sample() -> Element {
        let randomIndex = Int(rand()) % count
        return self[randomIndex]
    }
}

let array = [1, 2, 3, 4]

array.sample() // 2
array.sample() // 2
array.sample() // 3
array.sample() // 3

array.sample() // 1
array.sample() // 1
array.sample() // 3
array.sample() // 1

Solution 6 - Arrays

Another Swift 3 suggestion

private extension Array {
    var randomElement: Element {
        let index = Int(arc4random_uniform(UInt32(count)))
        return self[index]
    }
}

Solution 7 - Arrays

Following others answer but with Swift 2 support.

Swift 1.x

extension Array {
    func sample() -> T {
	    let index = Int(arc4random_uniform(UInt32(self.count)))
	    return self[index]
    }
}

Swift 2.x

extension Array {
    func sample() -> Element {
	    let index = Int(arc4random_uniform(UInt32(self.count)))
	    return self[index]
    }
}

E.g.:

let arr = [2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31]
let randomSample = arr.sample()

Solution 8 - Arrays

An alternative functional implementation with check for empty array.

func randomArrayItem<T>(array: [T]) -> T? {
  if array.isEmpty { return nil }
  let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
  return array[randomIndex]
}

randomArrayItem([1,2,3])

Solution 9 - Arrays

Here's an extension on Arrays with an empty array check for more safety:

extension Array {
    func sample() -> Element? {
        if self.isEmpty { return nil }
        let randomInt = Int(arc4random_uniform(UInt32(self.count)))
        return self[randomInt]
    }
}

You can use it as simple as this:

let digits = Array(0...9)
digits.sample() // => 6

If you prefer a Framework that also has some more handy features then checkout HandySwift. You can add it to your project via Carthage then use it exactly like in the example above:

import HandySwift    

let digits = Array(0...9)
digits.sample() // => 8

Additionally it also includes an option to get multiple random elements at once:

digits.sample(size: 3) // => [8, 0, 7]

Solution 10 - Arrays

Swift 3

import GameKit

func getRandomMessage() -> String {
    
    let messages = ["one", "two", "three"]
    
    let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: messages.count)
    
    return messages[randomNumber].description
    
}

Solution 11 - Arrays

Swift 3 - simple easy to use.

  1. Create Array

     var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]
    
  2. Create Random Color

     let randomColor = arc4random() % UInt32(arrayOfColors.count)
    
  3. Set that color to your object

     your item = arrayOfColors[Int(randomColor)]
    

Here is an example from a SpriteKit project updating a SKLabelNode with a random String:

    let array = ["one","two","three","four","five"]
    
    let randomNumber = arc4random() % UInt32(array.count)
    
    let labelNode = SKLabelNode(text: array[Int(randomNumber)])

Solution 12 - Arrays

If you want to be able to get more than one random element out of your array with no duplicates, GameplayKit has you covered:

import GameplayKit
let array = ["one", "two", "three", "four"]

let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array)

let firstRandom = shuffled[0]
let secondRandom = shuffled[1]

You have a couple choices for randomness, see GKRandomSource:

> The GKARC4RandomSource class uses an algorithm similar to that employed in arc4random family of C functions. (However, instances of this class are independent from calls to the arc4random functions.) > > The GKLinearCongruentialRandomSource class uses an algorithm that is faster, but less random, than the GKARC4RandomSource class. (Specifically, the low bits of generated numbers repeat more often than the high bits.) Use this source when performance is more important than robust unpredictability. > > The GKMersenneTwisterRandomSource class uses an algorithm that is slower, but more random, than the GKARC4RandomSource class. Use this source when it’s important that your use of random numbers not show repeating patterns and performance is of less concern.

Solution 13 - Arrays

I find using GameKit's GKRandomSource.sharedRandom() works best for me.

import GameKit

let array = ["random1", "random2", "random3"]

func getRandomIndex() -> Int {
    let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count)
    return randomNumber

or you could return the object at the random index selected. Make sure the function returns a String first, and then return the index of the array.

    return array[randomNumber]

Short and to the point.

Solution 14 - Arrays

There is a built-in method on Collection now:

let foods = ["πŸ•", "πŸ”", "🍣", "🍝"]
let myDinner = foods.randomElement()

If you want to extract up to n random elements from a collection you can add an extension like this one:

extension Collection {
    func randomElements(_ count: Int) -> [Element] {
        var shuffledIterator = shuffled().makeIterator()
        return (0..<count).compactMap { _ in shuffledIterator.next() }
    }
}

And if you want them to be unique you can use a Set, but the elements of the collection must conform to the Hashable protocol:

extension Collection where Element: Hashable {
    func randomUniqueElements(_ count: Int) -> [Element] {
        var shuffledIterator = Set(shuffled()).makeIterator()
        return (0..<count).compactMap { _ in shuffledIterator.next() }
    }
}

Solution 15 - Arrays

Latest swift3 code try it its working fine

 let imagesArray = ["image1.png","image2.png","image3.png","image4.png"]

        var randomNum: UInt32 = 0
        randomNum = arc4random_uniform(UInt32(imagesArray.count))
        wheelBackgroundImageView.image = UIImage(named: imagesArray[Int(randomNum)])

Solution 16 - Arrays

I figured out a very different way to do so using the new features introduced in Swift 4.2.

// πŸ‘‡πŸΌ - 1 
public func shufflePrintArray(ArrayOfStrings: [String]) -> String {
// - 2 
       let strings = ArrayOfStrings
//- 3
       var stringans =  strings.shuffled()
// - 4
        var countS = Int.random(in: 0..<strings.count)
// - 5
        return stringans[countS] 
}
    

  1. we declared a function with parameters taking an array of Strings and returning a String.

  2. Then we take the ArrayOfStrings in a variable.

  3. Then we call the shuffled function and store that in a variable. (Only supported in 4.2)

  4. Then we declare a variable which saves a shuffled value of total count of the String.

  5. Lastly we return the shuffled string at the index value of countS.

It is basically shuffling the array of strings and then also have a random pick of number of the total number of count and then returning the random index of the shuffled array.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFelaView Question on Stackoverflow
Solution 1 - ArraysLucas DerraughView Answer on Stackoverflow
Solution 2 - ArraysPhae DeepskyView Answer on Stackoverflow
Solution 3 - ArraysAndrey GordeevView Answer on Stackoverflow
Solution 4 - ArraysMilosView Answer on Stackoverflow
Solution 5 - ArraysNatashaTheRobotView Answer on Stackoverflow
Solution 6 - ArraysslammerView Answer on Stackoverflow
Solution 7 - ArraysAidan GomezView Answer on Stackoverflow
Solution 8 - ArraysEvgeniiView Answer on Stackoverflow
Solution 9 - ArraysJeehutView Answer on Stackoverflow
Solution 10 - ArraysDazzleView Answer on Stackoverflow
Solution 11 - ArraysTimmy SorensenView Answer on Stackoverflow
Solution 12 - ArraysbcattleView Answer on Stackoverflow
Solution 13 - Arraysdjames04View Answer on Stackoverflow
Solution 14 - ArraysGigisommoView Answer on Stackoverflow
Solution 15 - ArraysGangireddy Rami ReddyView Answer on Stackoverflow
Solution 16 - ArraysCoffee and WafflesView Answer on Stackoverflow