arrays swift random shuffle

arrays - Obtenga elementos aleatorios de la matriz en Swift



random shuffle (5)

¿O alguien tiene una solución mejor / más elegante para esto?

Hago. Algorítmicamente mejor que la respuesta aceptada, que cuenta 1 operaciones arc4random_uniform para una arc4random_uniform aleatoria completa, simplemente podemos elegir n valores en n operaciones arc4random_uniform .

Y en realidad, obtuve dos formas de hacerlo mejor que la respuesta aceptada:

Mejor solución

extension Array { /// Picks `n` random elements (partial Fisher-Yates shuffle approach) subscript (randomPick n: Int) -> [Element] { var copy = self for i in stride(from: count - 1, to: count - n - 1, by: -1) { let j = Int(arc4random_uniform(UInt32(i + 1))) if j != i { swap(&copy[i], &copy[j]) } } return Array(copy.suffix(n)) } }

Mejor solución

La siguiente solución es dos veces más rápida que la anterior.

para Swift 3.0 y 3.1

extension Array { /// Picks `n` random elements (partial Fisher-Yates shuffle approach) subscript (randomPick n: Int) -> [Element] { var copy = self for i in stride(from: count - 1, to: count - n - 1, by: -1) { copy.swapAt(i, Int(arc4random_uniform(UInt32(i + 1)))) } return Array(copy.suffix(n)) } }

para Swift 3.2 y 4.x

let digits = Array(0...9) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] let pick3digits = digits[randomPick: 3] // [8, 9, 0]

Uso:

extension Array { func getRandomElements() -> (T, T, T) { return (self[Int(arc4random()) % Int(count)], self[Int(arc4random()) % Int(count)], self[Int(arc4random()) % Int(count)]) } } let names = ["Peter", "Steve", "Max", "Sandra", "Roman", "Julia"] names.getRandomElements()

Tengo una matriz como:

var names: String = [ "Peter", "Steve", "Max", "Sandra", "Roman", "Julia" ]

Me gustaría obtener 3 elementos aleatorios de esa matriz. Vengo de C # pero rápidamente no estoy seguro de por dónde empezar. Creo que debería barajar la matriz primero y luego elegir los primeros 3 elementos, por ejemplo.

Traté de barajarlo con la siguiente extensión:

extension Array { mutating func shuffle() { for _ in 0..<10 { sort { (_,_) in arc4random() < arc4random() } } } }

pero luego dice "''()'' no es convertible a ''[Int]''" en la ubicación de "shuffle ()".

Para elegir una serie de elementos que uso:

var randomPicks = names[0..<4];

que se ve bien hasta ahora.

¿Cómo barajar? ¿O alguien tiene una solución mejor / más elegante para esto?


Puede definir una extensión en Array:

extension Array where Element: Hashable { func pickUniqueInValue(_ n: Int) -> [Element] { let set: Set<Element> = Set(self) guard set.count >= n else { fatalError("The array has to have at least /(n) unique values") } guard n >= 0 else { fatalError("The number of elements to be picked must be positive") } return Array(set.prefix(upTo: set.index(set.startIndex, offsetBy: n))) } } [ "Peter", "Steve", "Max", "Sandra", "Roman", "Julia" ].pickUniqueInValue(3)

Si la matriz inicial puede tener duplicados y desea unicidad en el valor:

extension Array where Element: Hashable { func pickUniqueInValue(_ n: Int) -> [Element] { let set: Set<Element> = Set(self) guard set.count >= n else { fatalError("The array has to have at least /(n) unique values") } guard n >= 0 else { fatalError("The number of elements to be picked must be positive") } return Array(set.prefix(upTo: set.index(set.startIndex, offsetBy: n))) } } [ "Peter", "Steve", "Max", "Sandra", "Roman", "Julia" ].pickUniqueInValue(3)


También puede usar arc4random () para elegir tres elementos de la matriz. Algo como esto:

let playlist = ["Nothing Else Matters", "Stairway to Heaven", "I Want to Break Free", "Yesterday"] let index = Int(arc4random_uniform(UInt32(playlist.count))) let song = playlist[index]

Este es solo un ejemplo, también podría incluir lógica en la función para obtener un nombre diferente para cada uno.


Swift 4.1 y abajo

if let song = playlist.randomElement() { print(song) } else { print("Empty playlist.") }

Swift 4.2 y superior

extension Array { func pick(_ n: Int) -> [Element] { guard count >= n else { fatalError("The count has to be at least /(n)") } guard n >= 0 else { fatalError("The number of elements to be picked must be positive") } let shuffledIndices = indices.shuffled().prefix(upTo: n) return shuffledIndices.map {self[$0]} } } [ "Peter", "Steve", "Max", "Sandra", "Roman", "Julia" ].pick(3)


Xcode 11 • Swift 5.1

extension Array { /// Returns an array containing this sequence shuffled var shuffled: Array { var elements = self return elements.shuffle() } /// Shuffles this sequence in place @discardableResult mutating func shuffle() -> Array { let count = self.count indices.lazy.dropLast().forEach { swapAt($0, Int(arc4random_uniform(UInt32(count - $0))) + $0) } return self } var chooseOne: Element { return self[Int(arc4random_uniform(UInt32(count)))] } func choose(_ n: Int) -> Array { return Array(shuffled.prefix(n)) } }

Prueba de patio de recreo

var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"] let shuffledAlphabet = alphabet.shuffled let letter = alphabet.chooseOne var numbers = Array(0...9) let shuffledNumbers = numbers.shuffled shuffledNumbers // [8, 9, 3, 6, 0, 1, 4, 2, 5, 7] numbers // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] numbers.shuffle() // mutate it [6, 0, 2, 3, 9, 1, 5, 7, 4, 8] numbers // [6, 0, 2, 3, 9, 1, 5, 7, 4, 8] let pick3numbers = numbers.choose(3) // [8, 9, 2]

import UIKit extension Array { /// Returns an array containing this sequence shuffled var shuffled: Array { var elements = self return elements.shuffle() } /// Shuffles this sequence in place @discardableResult mutating func shuffle() -> Array { let count = self.count indices.lazy.dropLast().forEach { guard case let index = Int(arc4random_uniform(UInt32(count - $0))) + $0, index != $0 else { return } swap(&self[$0], &self[index]) } return self } var chooseOne: Element { return self[Int(arc4random_uniform(UInt32(count)))] } func choose(_ n: Int) -> Array { return Array(shuffled.prefix(n)) } }

extension Array { /// Picks `n` random elements (straightforward approach) subscript (randomPick n: Int) -> [Element] { var indices = [Int](0..<count) var randoms = [Int]() for _ in 0..<n { randoms.append(indices.remove(at: Int(arc4random_uniform(UInt32(indices.count))))) } return randoms.map { self[$0] } } }