programming - Shuffle array swift 3
the swift programming language pdf (4)
Hay un shuffle de fisher-yates en Gamekit:
import GameKit
let unshuffledArray = [1,2,3,4]
let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray)
print(shuffledArray)
También puede pasar y almacenar una semilla aleatoria, de modo que obtenga la misma secuencia de valores aleatorios pseudoaleatorios cada vez que proporcione la misma semilla en caso de que necesite recrear una simulación.
import GameKit
let unshuffledArray = [1,2,3,4]
let randomSource = GKLinearCongruentialRandomSource(seed: 1)
let shuffledArray = randomSource.arrayByShufflingObjects(in: unshuffledArray)
//Always [1,4,2,3]
print(shuffledArray)
¿Cómo puedo convertir la siguiente función a
swift 3
?
Actualmente, obtener un
Binary operator ''..<'' cannot be applied to operands of type ''Int'' and ''Self.IndexDistance''
error.
extension MutableCollection where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don''t shuffle
if count < 2 { return }
for i in 0..<count - 1 { //error takes place here
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
referencia: https://stackoverflow.com/a/24029847/5222077
Puedes usar la Extensión NSArray del marco de GameplayKit para esto:
import GameplayKit
extension Collection {
func shuffled() -> [Iterator.Element] {
let shuffledArray = (self as? NSArray)?.shuffled()
let outputArray = shuffledArray as? [Iterator.Element]
return outputArray ?? []
}
mutating func shuffle() {
if let selfShuffled = self.shuffled() as? Self {
self = selfShuffled
}
}
}
// Usage example:
var numbers = [1,2,3,4,5]
numbers.shuffle()
print(numbers) // output example: [2, 3, 5, 4, 1]
print([10, "hi", 9.0].shuffled()) // output example: [hi, 10, 9]
Sugeriría simplemente barajar matrices en lugar de tratar de extender esto a las colecciones en general:
extension Array {
mutating func shuffle () {
for i in (0..<self.count).reversed() {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(self[ix1], self[ix2]) = (self[ix2], self[ix1])
}
}
}
count
devuelve un
IndexDistance
que es el tipo que describe la distancia entre dos índices de recopilación.
IndexDistance
se requiere para ser un
SignedInteger
, pero no necesita ser un
Int
y puede ser diferente de
Index
.
Por lo tanto, no es posible crear el rango
0..<count - 1
.
Una solución es usar
startIndex
y
endIndex
lugar de
0
y
count
:
extension MutableCollection where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffle() {
// empty and single-element collections don''t shuffle
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
let j = Int(arc4random_uniform(UInt32(endIndex - i))) + i
if i != j {
swap(&self[i], &self[j])
}
}
}
}
Otra ventaja es que esto también funciona correctamente con cortes de matriz (donde el índice del primer elemento no es necesariamente cero).
Tenga en cuenta que de acuerdo con las nuevas
"Directrices de diseño de API Swift"
,
shuffle()
es el nombre "apropiado" para un método aleatorio mutante y
shuffled()
para la contraparte no mutante que devuelve una matriz:
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Iterator.Element] {
var list = Array(self)
list.shuffle()
return list
}
}
Actualización: se ha agregado una versión de Swift 3 (aún más general) a ¿Cómo barajo una matriz en Swift? mientras tanto.
Para
Swift 4 (Xcode 9)
uno tiene que reemplazar la llamada a la función
swap()
por una llamada al método
swapAt()
de la colección.
Además, la restricción sobre el tipo de
Index
ya no es necesaria:
extension MutableCollection {
/// Shuffle the elements of `self` in-place.
mutating func shuffle() {
for i in indices.dropLast() {
let diff = distance(from: i, to: endIndex)
let j = index(i, offsetBy: numericCast(arc4random_uniform(numericCast(diff))))
swapAt(i, j)
}
}
}
Consulte
SE-0173 Agregar
MutableCollection.swapAt(_:_:)
para obtener más información sobre
swapAt
.
A partir de
Swift 4.2
(Xcode 10, actualmente en versión beta), con la implementación de la
Unificación aleatoria SE-0202
,
shuffle()
y
shuffled()
son parte de la biblioteca estándar de Swift.