Elige un elemento aleatorio de una matriz

Supongamos que tengo una matriz y quiero elegir un elemento al azar.

¿Cuál sería la forma más sencilla de hacer esto?

La forma obvia sería array[random index] . Pero tal vez hay algo así como la array.sample de array.sample . O, si no, ¿podría crearse tal método utilizando una extensión?

Swift 4.2 y superior

El nuevo enfoque recomendado es un método randomElement() : randomElement() . Devuelve un opcional para evitar el caso vacío que asumí anteriormente.

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

Si no creas la matriz y no se garantiza el conteo> 0, deberías hacer algo como:

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

Swift 4.1 y abajo

Solo para responder a su pregunta, puede hacer esto para lograr una selección de matriz aleatoria:

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

Los lanzamientos son feos, pero creo que son necesarios a menos que alguien más tenga otra forma.

Riffing sobre lo que dijo Lucas, podrías crear una extensión para la clase Array de esta manera:

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

Por ejemplo:

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

Swift 4 versión:

 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)))] } } 

En Swift 2.2 esto se puede generalizar para que tengamos:

 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 

Primero, implementando propiedad random estática para UnsignedIntegerType s:

 import Darwin func sizeof  (_: () -> 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) } } 

Luego, para ClosedInterval s con límites UnsignedIntegerType :

 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)) } } 

Luego (un poco más involucrado), para ClosedInterval s con límites SignedIntegerType (usando los métodos de ayuda descritos más adelante):

 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) } } 

... donde los métodos de ayuda unsignedDistanceTo , unsignedDistanceFromMin y plusMinIntMax se pueden implementar de la siguiente manera:

 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) } } } 

Finalmente, para todas las colecciones donde 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] } } 

... que se puede optimizar un poco para el entero Range s:

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

Puede usar la función aleatoria () incorporada de Swift para la extensión:

 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 

Otra sugerencia de Swift 3

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

Los siguientes responden pero con el soporte de Swift 2.

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] } } 

P.ej:

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

Una implementación funcional alternativa con verificación de matriz vacía.

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

Aquí hay una extensión en matrices con una comprobación de matriz vacía para mayor seguridad:

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

Puedes usarlo tan simple como esto :

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

Si prefiere un Framework que también tenga algunas características más útiles, realice la compra de HandySwift . Puede agregarlo a su proyecto a través de Carthage y luego usarlo exactamente como en el ejemplo anterior:

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

Además, también incluye una opción para obtener múltiples elementos aleatorios a la vez :

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

Swift 3

importar GameKit

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

Swift 3: fácil de usar.

  1. Crear matriz

     var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green] 
  2. Crear color aleatorio

     let randomColor = arc4random() % UInt32(arrayOfColors.count) 
  3. Establezca ese color a su objeto

     your item = arrayOfColors[Int(randomColor)] 

Aquí hay un ejemplo de un proyecto de SpriteKit que actualiza un SKLabelNode con una String aleatoria:

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

Si quieres poder obtener más de un elemento aleatorio de tu matriz sin duplicados , GameplayKit te tiene cubierto:

 import GameplayKit let array = ["one", "two", "three", "four"] let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array) let firstRandom = shuffled[0] let secondRandom = shuffled[1] 

Tienes un par de opciones para la aleatoriedad, mira GKRandomSource :

La clase GKARC4RandomSource usa un algoritmo similar al empleado en la familia arc4random de funciones C. (Sin embargo, las instancias de esta clase son independientes de las llamadas a las funciones arc4random).

La clase GKLinearCongruentialRandomSource utiliza un algoritmo que es más rápido, pero menos aleatorio, que la clase GKARC4RandomSource. (Específicamente, los bits bajos de los números generados se repiten con más frecuencia que los bits altos). Utilice esta fuente cuando el rendimiento sea más importante que la impredictibilidad robusta.

La clase GKMersenneTwisterRandomSource utiliza un algoritmo que es más lento, pero más aleatorio, que la clase GKARC4RandomSource. Use esta fuente cuando sea importante que su uso de números aleatorios no muestre patrones repetitivos y el rendimiento es menos preocupante.

Me parece que usar GKRandomSource.sharedRandom () de GameKit funciona mejor para mí.

 import GameKit let array = ["random1", "random2", "random3"] func getRandomIndex() -> Int { let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count) return randomNumber 

o puede devolver el objeto en el índice aleatorio seleccionado. Asegúrese de que la función devuelva primero un String y luego devuelva el índice de la matriz.

  return array[randomNumber] 

Corto y al grano.

El último código de swift3 lo prueba funciona bien

  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)])