¿Cómo barajo una matriz en Swift?

305

¿Cómo aleatorizo ​​o barajo los elementos dentro de una matriz en Swift? Por ejemplo, si mi matriz consta de 52 cartas, quiero barajar la matriz para barajar la baraja.

mpatzer
fuente
2
Esto no es específico de ningún idioma. Simplemente aplique cualquier algoritmo de barajado ...
Gabriele Petronella
8
@ Mitrandir Eso no es cierto. En Ruby uno iría por array.shuffle. No hay necesidad de implementar su propia versión. Supongo que OP estaba buscando algo similar.
Linus Oleander
1
Tenga cuidado, sin embargo, no use cualquier algoritmo de barajado para barajar un mazo de cartas.
njzk2

Respuestas:

627

Esta respuesta detalla cómo barajar con un algoritmo rápido y uniforme (Fisher-Yates) en Swift 4.2+ y cómo agregar la misma función en las diversas versiones anteriores de Swift. Los nombres y el comportamiento de cada versión de Swift coinciden con los métodos de clasificación mutantes y no mutantes para esa versión.

Swift 4.2+

shuffley shuffledson nativos a partir de Swift 4.2. Ejemplo de uso:

let x = [1, 2, 3].shuffled()
// x == [2, 3, 1]

let fiveStrings = stride(from: 0, through: 100, by: 5).map(String.init).shuffled()
// fiveStrings == ["20", "45", "70", "30", ...]

var numbers = [1, 2, 3, 4]
numbers.shuffle()
// numbers == [3, 2, 1, 4]

Swift 4.0 y 4.1

Estas extensiones agregan un shuffle()método a cualquier colección mutable (matrices y buffers mutables inseguros) y un shuffled()método a cualquier secuencia:

extension MutableCollection {
    /// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            // Change `Int` in the next line to `IndexDistance` in < Swift 4.1
            let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
            let i = index(firstUnshuffled, offsetBy: d)
            swapAt(firstUnshuffled, i)
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}

El mismo uso que en los ejemplos de Swift 4.2 anteriores.


Swift 3

Estas extensiones agregan un shuffle()método a cualquier colección mutable y un shuffled()método a cualquier secuencia:

extension MutableCollection where Indices.Iterator.Element == Index {
    /// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            // Change `Int` in the next line to `IndexDistance` in < Swift 3.2
            let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
            guard d != 0 else { continue }
            let i = index(firstUnshuffled, offsetBy: d)
            self.swapAt(firstUnshuffled, i)
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Iterator.Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}

El mismo uso que en los ejemplos de Swift 4.2 anteriores.


Swift 2

(lenguaje obsoleto: no puede usar Swift 2.x para publicar en iTunes Connect a partir de julio de 2018)

extension MutableCollectionType 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 startIndex ..< endIndex - 1 {
            let j = Int(arc4random_uniform(UInt32(count - i))) + i
            guard i != j else { continue }
            swap(&self[i], &self[j])
        }
    }
}

extension CollectionType {
    /// Return a copy of `self` with its elements shuffled.
    func shuffle() -> [Generator.Element] {
        var list = Array(self)
        list.shuffleInPlace()
        return list
    }
}

Uso:

[1, 2, 3].shuffle()
// [2, 3, 1]

let fiveStrings = 0.stride(through: 100, by: 5).map(String.init).shuffle()
// ["20", "45", "70", "30", ...]

var numbers = [1, 2, 3, 4]
numbers.shuffleInPlace()
// [3, 2, 1, 4]

Swift 1.2

(lenguaje obsoleto: no puede usar Swift 1.x para publicar en iTunes Connect a partir de julio de 2018)

shuffle como un método de matriz mutante

Esta extensión le permitirá barajar una Arrayinstancia mutable en su lugar:

extension Array {
    mutating func shuffle() {
        if count < 2 { return }
        for i in 0..<(count - 1) {
            let j = Int(arc4random_uniform(UInt32(count - i))) + i
            swap(&self[i], &self[j])
        }
    }
}
var numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.shuffle()                     // e.g., numbers == [6, 1, 8, 3, 2, 4, 7, 5]

shuffled como un método de matriz no mutante

Esta extensión le permitirá recuperar una copia barajada de una Arrayinstancia:

extension Array {
    func shuffled() -> [T] {
        if count < 2 { return self }
        var list = self
        for i in 0..<(list.count - 1) {
            let j = Int(arc4random_uniform(UInt32(list.count - i))) + i
            swap(&list[i], &list[j])
        }
        return list
    }
}
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let mixedup = numbers.shuffled()     // e.g., mixedup == [6, 1, 8, 3, 2, 4, 7, 5]
Nate Cook
fuente
1
En caso de que desee la versión de la función en Swift 1.2, necesita un poco de actualización a medida countElementsque desaparece, y su reemplazo count, ahora devuelve un, T.Index.Distancepor lo que la restricción debe estar activada C.Index.Distance == Int. Esta versión debería funcionar: gist.github.com/airspeedswift/03d07a9dc86fabdc370f
Airspeed Velocity
2
Esos son los resultados reales: Fisher-Yates debería devolver una permutación aleatoria imparcial de la fuente, por lo que no es necesario que se mueva un elemento en particular. No es una garantía de que no hay elemento se mueve más de una vez, pero a veces el "movimiento" es el mismo índice. El caso más simple es pensar: ¿ [1, 2].shuffled()debería volver eso [2, 1]siempre?
Nate Cook
1
Agregué if count > 0en la parte superior de la función de matriz mutante, para evitar recibir un "error fatal: no se puede formar Range con end <start" cuando se pasa una matriz vacía.
Carl Smith
3
@ Jan: Sí, agregue guard i != j else { continue }antes del intercambio. Archivé un radar, pero el nuevo comportamiento es intencional.
Nate Cook
3
En realidad, shuffleInPlacepuede bloquearse si los índices de recopilación no comienzan en cero, por ejemplo, para un segmento de matriz. for i in 0..<count - 1 debería ser for i in startIndex ..< endIndex - 1(y luego la conversión a Swift 3 se vuelve casi trivial).
Martin R
131

Editar: Como se señaló en otras respuestas, Swift 4.2 finalmente agrega la generación de números aleatorios a la biblioteca estándar, completa con la combinación aleatoria de matrices.

Sin embargo, el GKRandom/ GKRandomDistributionsuite en GameplayKit todavía puede ser útil con el nuevoRandomNumberGenerator protocolo: si agrega extensiones a los RNG de GameplayKit para cumplir con el nuevo protocolo de biblioteca estándar, puede obtener fácilmente:

  • RNG enviables (que pueden reproducir una secuencia "aleatoria" cuando sea necesario para la prueba)
  • RNG que sacrifican la robustez por la velocidad
  • RNG que producen distribuciones no uniformes

... y aún utilizo las nuevas API aleatorias "nativas" en Swift.

El resto de esta respuesta se refiere a tales RNG y / o su uso en compiladores Swift más antiguos.


Ya hay algunas buenas respuestas aquí, así como algunas buenas ilustraciones de por qué escribir su propio shuffle puede ser propenso a errores si no tiene cuidado.

En iOS 9, macOS 10.11 y tvOS 9 (o posterior), no tiene que escribir el suyo. Hay una implementación eficiente y correcta de Fisher-Yates en GameplayKit (que, a pesar del nombre, no es solo para juegos).

Si solo quieres un shuffle único:

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

Si desea poder replicar un shuffle o una serie de shuffles, elija y siembre una fuente aleatoria específica; p.ej

let lcg = GKLinearCongruentialRandomSource(seed: mySeedValue)
let shuffled = lcg.arrayByShufflingObjects(in: array)

En iOS 10 / macOS 10.12 / tvOS 10, también hay una sintaxis conveniente para barajar a través de una extensión activada NSArray. Por supuesto, eso es un poco engorroso cuando usas un Swift Array(y pierde su tipo de elemento al volver a Swift):

let shuffled1 = (array as NSArray).shuffled(using: random) // -> [Any]
let shuffled2 = (array as NSArray).shuffled() // use default random source

Pero es bastante fácil hacer un envoltorio Swift que conserve el tipo:

extension Array {
    func shuffled(using source: GKRandomSource) -> [Element] {
        return (self as NSArray).shuffled(using: source) as! [Element]
    }
    func shuffled() -> [Element] {
        return (self as NSArray).shuffled() as! [Element]
    }
}
let shuffled3 = array.shuffled(using: random)
let shuffled4 = array.shuffled()
rickster
fuente
66
Me hace preguntarme qué otras utilidades útiles se pueden encontrar en GameplayKit que nunca he explorado.
Richard Venable
66
Búsqueda de gráficos, búsqueda de árboles, sistemas de reglas ... muchas cosas que son útiles tanto en el diseño del juego como en otros.
rickster
55
En Swift 3 / iOS 10, esto se ha cambiado a:let shuffled = lcg.arrayByShufflingObjects(in: array)
Evan Pon
30

¡En Swift 2.0 , GameplayKit puede venir al rescate! (compatible con iOS9 o posterior)

import GameplayKit

func shuffle() {
    array = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(array)
}
bluenowhere
fuente
55
importar GameplayKit solo para mezclar la matriz no parece una gran idea
Lope
3
¿Por qué? Es parte del sistema, no se agrega al binario.
Abizern
3
También puede ampliar la importación de manera simpleimport GameplayKit.GKRandomSource
JRG-Developer el
26

Aquí hay algo posiblemente un poco más corto:

sorted(a) {_, _ in arc4random() % 2 == 0}
Jean Le Moignan
fuente
1
@moby La sortfunción necesita un cierre para ordenar elementos. Este cierre toma dos parámetros (elem1, elem2) y debe devolver verdadero si el primer valor debe aparecer antes del segundo valor, y falso de lo contrario. Si devolvemos un booleano aleatorio en su lugar ... entonces simplemente mezclamos todo :)
Jean Le Moignan
2
¿Algún matemático aquí para confirmar o refutar?
Jean Le Moignan
99
Como pjs señaló en respuesta a otra respuesta muy similar, esto no generará una distribución uniforme de los resultados. Use Fisher-Yates Shuffle como se muestra en la respuesta de Nate Cook.
Rob
1
Este es un truco inteligente, pero es abismal en términos de calidad de la barajadura. Por un lado, este cierre debería usarse arc4random_uniform(), porque actualmente está sujeto al sesgo del módulo. En segundo lugar, la salida depende en gran medida del algoritmo de clasificación (que no conocemos sin mirar la fuente).
Alexander - Restablece a Mónica el
1
Continuando con este enfoque más simple, parece funcionar bastante bien: collection.sorted { _,_ in arc4random_uniform(1) == 0 }
markiv
7

Tomando el algoritmo de Nate, quería ver cómo se vería esto con Swift 2 y las extensiones de protocolo.

Esto es lo que se me ocurrió.

extension MutableCollectionType where Self.Index == Int {
    mutating func shuffleInPlace() {
        let c = self.count
        for i in 0..<(c - 1) {
            let j = Int(arc4random_uniform(UInt32(c - i))) + i
            swap(&self[i], &self[j])
        }
    }
}

extension MutableCollectionType where Self.Index == Int {
    func shuffle() -> Self {
        var r = self
        let c = self.count
        for i in 0..<(c - 1) {
            let j = Int(arc4random_uniform(UInt32(c - i))) + i
            swap(&r[i], &r[j])
        }
        return r
    }
}

Ahora cualquier MutableCollectionType puede usar estos métodos dado que los usa IntcomoIndex

Chris Wagner
fuente
6

En mi caso, tuve algunos problemas para intercambiar objetos en Array. Luego me rasqué la cabeza y fui a reinventar la rueda.

// swift 3.0 ready
extension Array {

    func shuffled() -> [Element] {
        var results = [Element]()
        var indexes = (0 ..< count).map { $0 }
        while indexes.count > 0 {
            let indexOfIndexes = Int(arc4random_uniform(UInt32(indexes.count)))
            let index = indexes[indexOfIndexes]
            results.append(self[index])
            indexes.remove(at: indexOfIndexes)
        }
        return results
    }

}
Kaz Yoshikawa
fuente
5

Esta es una versión de la implementación de Nate del shuffle Fisher-Yates para Swift 4 (Xcode 9).

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

extension Collection {
    /// Return a copy of `self` with its elements shuffled
    func shuffled() -> [Element] {
        var list = Array(self)
        list.shuffle()
        return list
    }
}

Los cambios son:

  • La restricción Indices.Iterator.Element == Indexahora es parte de laCollection protocolo y ya no es necesario imponerla a la extensión.
  • El intercambio de elementos debe hacerse llamando swapAt()a la colección, compare SE-0173 AgregarMutableCollection.swapAt(_:_:) .
  • Elementes un alias para Iterator.Element.
Martin R
fuente
3

Esto es lo que uso:

func newShuffledArray(array:NSArray) -> NSArray {
    var mutableArray = array.mutableCopy() as! NSMutableArray
    var count = mutableArray.count
    if count>1 {
        for var i=count-1;i>0;--i{
            mutableArray.exchangeObjectAtIndex(i, withObjectAtIndex: Int(arc4random_uniform(UInt32(i+1))))
        }
    }
    return mutableArray as NSArray
}
iliketopgun
fuente
3

Swift 4 Mezcla los elementos de una matriz en un bucle for donde i es la relación de mezcla

var cards = [Int]() //Some Array
let i = 4 // is the mixing ratio
func shuffleCards() {
    for _ in 0 ..< cards.count * i {
        let card = cards.remove(at: Int(arc4random_uniform(UInt32(cards.count))))
        cards.insert(card, at: Int(arc4random_uniform(UInt32(cards.count))))
    }
}

O con extensión Int

func shuffleCards() {
    for _ in 0 ..< cards.count * i {
        let card = cards.remove(at: cards.count.arc4random)
        cards.insert(card, at: cards.count.arc4random)
    }
}
extension Int {
    var arc4random: Int {
        if self > 0 {
            print("Arc for random positiv self \(Int(arc4random_uniform(UInt32(self))))")
        return Int(arc4random_uniform(UInt32(self)))
        } else if self < 0 {
            print("Arc for random negotiv self \(-Int(arc4random_uniform(UInt32(abs(self)))))")
            return -Int(arc4random_uniform(UInt32(abs(self))))
        } else {
            print("Arc for random equal 0")
            return 0
        }
    }
}
Sergei
fuente
2

Solución Swift 3, siguiendo la respuesta de @Nate Cook: (funciona si el índice comienza con 0, vea los comentarios a continuación)

extension Collection {
    /// Return a copy of `self` with its elements shuffled
    func shuffle() -> [Generator.Element] {
        var list = Array(self)
        list.shuffleInPlace()
        return list
    } }

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 }
        let countInt = count as! Int

    for i in 0..<countInt - 1 {
        let j = Int(arc4random_uniform(UInt32(countInt - i))) + i
            guard i != j else { continue }
            swap(&self[i], &self[j])
        }
    }
}
Anson Yao
fuente
1
Esto puede bloquearse si los índices de recopilación comienzan en 0, por ejemplo, para un segmento de matriz. Intenta correr var a = [1, 2, 3, 4, 5, 6][3..<6]; a.shuffleInPlace()varias veces. - Consulte stackoverflow.com/a/37843901/1187415 para obtener una solución correcta.
Martin R
2

Así es como se hace de la manera más simple. import Gamplaykita su VC y use el siguiente código. Probado en Xcode 8.

 import GameplayKit

 let array: NSArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]

 override func viewDidLoad() {
    super.viewDidLoad()

    print(array.shuffled())  
}

Si desea obtener una cadena aleatoria de una matriz, puede usar el siguiente código.

func suffleString() {

    let ShuffleArray = array.shuffled()

    suffleString.text = ShuffleArray.first as? String

    print(suffleString.text!)

}
Joe
fuente
2

Con Swift 3, si desea mezclar una matriz en su lugar u obtener una nueva matriz aleatoria de una matriz, AnyIteratorpuede ayudarlo. La idea es crear una matriz de índices a partir de su matriz, mezclar esos índices con una AnyIteratorinstancia y swap(_:_:)función y asignar cada elemento de esta AnyIteratorinstancia con el elemento correspondiente de la matriz.


El siguiente código de Playground muestra cómo funciona:

import Darwin // required for arc4random_uniform

let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
var indexArray = Array(array.indices)
var index = indexArray.endIndex

let indexIterator: AnyIterator<Int> = AnyIterator {
    guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
        else { return nil }

    index = nextIndex
    let randomIndex = Int(arc4random_uniform(UInt32(index)))
    if randomIndex != index {
        swap(&indexArray[randomIndex], &indexArray[index])
    }

    return indexArray[index]
}

let newArray = indexIterator.map { array[$0] }
print(newArray) // may print: ["Jock", "Ellie", "Sue Ellen", "JR", "Pamela", "Bobby"]

Puede refactorizar el código anterior y crear una shuffled()función dentro de una Arrayextensión para obtener una nueva matriz aleatoria de una matriz:

import Darwin // required for arc4random_uniform

extension Array {

    func shuffled() -> Array<Element> {
        var indexArray = Array<Int>(indices)        
        var index = indexArray.endIndex

        let indexIterator = AnyIterator<Int> {
            guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
                else { return nil }

            index = nextIndex                
            let randomIndex = Int(arc4random_uniform(UInt32(index)))
            if randomIndex != index {
                swap(&indexArray[randomIndex], &indexArray[index])
            }

            return indexArray[index]
        }

        return indexIterator.map { self[$0] }
    }

}

Uso:

let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
let newArray = array.shuffled()
print(newArray) // may print: ["Bobby", "Pamela", "Jock", "Ellie", "JR", "Sue Ellen"]
let emptyArray = [String]()
let newEmptyArray = emptyArray.shuffled()
print(newEmptyArray) // prints: []

Como alternativa al código anterior, puede crear una shuffle()función dentro de una Arrayextensión para barajar una matriz en su lugar:

import Darwin // required for arc4random_uniform

extension Array {

    mutating func shuffle() {
        var indexArray = Array<Int>(indices)
        var index = indexArray.endIndex

        let indexIterator = AnyIterator<Int> {
            guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
                else { return nil }

            index = nextIndex                
            let randomIndex = Int(arc4random_uniform(UInt32(index)))
            if randomIndex != index {
                swap(&indexArray[randomIndex], &indexArray[index])
            }

            return indexArray[index]
        }

        self = indexIterator.map { self[$0] }
    }

}

Uso:

var mutatingArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
mutatingArray.shuffle()
print(mutatingArray) // may print ["Sue Ellen", "Pamela", "Jock", "Ellie", "Bobby", "JR"]
Imanou Petit
fuente
1

También puede usar la swapfunción genérica e implementar el mencionado Fisher-Yates:

for idx in 0..<arr.count {
  let rnd = Int(arc4random_uniform(UInt32(idx)))
  if rnd != idx {
    swap(&arr[idx], &arr[rnd])
  }
}

o menos detallado:

for idx in 0..<steps.count {
  swap(&steps[idx], &steps[Int(arc4random_uniform(UInt32(idx)))])
}
Daniel Bauke
fuente
2
Esto sufre, como mínimo, un error grave por un error descrito aquí por el cual un valor siempre se intercambia desde su posición original. Esto se remedia con let rnd = Int(arc4random_uniform(UInt32(idx + 1))). Además, en el año fiscal, generalmente itera de arr.count - 1abajo a 1(o si itera de 0a arr.count - 1, elige el índice como muestra Nate en la respuesta aceptada). Vea la sección Algoritmo moderno de la discusión de Fisher-Yates.
Rob
1

¡¡trabajos!!. organismos es la matriz para barajar.

extension Array
{
    /** Randomizes the order of an array's elements. */
    mutating func shuffle()
    {
        for _ in 0..<10
        {
            sort { (_,_) in arc4random() < arc4random() }
        }
    }
}

var organisms = [
    "ant",  "bacteria", "cougar",
    "dog",  "elephant", "firefly",
    "goat", "hedgehog", "iguana"]

print("Original: \(organisms)")

organisms.shuffle()

print("Shuffled: \(organisms)")
Vimal
fuente
0

Así es como mezclar una matriz con una semilla en Swift 3.0.

extension MutableCollection where Indices.Iterator.Element == Index {
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }


        for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            srand48(seedNumber)
            let number:Int = numericCast(unshuffledCount)
            let r = floor(drand48() * Double(number))

            let d: IndexDistance = numericCast(Int(r))
            guard d != 0 else { continue }
            let i = index(firstUnshuffled, offsetBy: d)
            swap(&self[firstUnshuffled], &self[i])
        }
    }
}
Tayo119
fuente
0
let shuffl = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: arrayObject)
Rohit Sisodia
fuente
0

Esto es lo que uso:

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]
Daniel Illescas
fuente
0

Ejemplo simple:

extension Array {
    mutating func shuffled() {
        for _ in self {
            // generate random indexes that will be swapped
            var (a, b) = (Int(arc4random_uniform(UInt32(self.count - 1))), Int(arc4random_uniform(UInt32(self.count - 1))))
            if a == b { // if the same indexes are generated swap the first and last
                a = 0
                b = self.count - 1
            }
            swap(&self[a], &self[b])
        }
    }
}

var array = [1,2,3,4,5,6,7,8,9,10]
array.shuffled()
print(array) // [9, 8, 3, 5, 7, 6, 4, 2, 1, 10]
Poli
fuente
0

Extensión de matriz de trabajo (mutante y no mutante)

Swift 4.1 / Xcode 9

La respuesta principal está en desuso, por lo que me encargué de crear mi propia extensión para mezclar una matriz en la versión más nueva de Swift, Swift 4.1 (Xcode 9):

extension Array {

// Non-mutating shuffle
    var shuffled : Array {
        let totalCount : Int = self.count
        var shuffledArray : Array = []
        var count : Int = totalCount
        var tempArray : Array = self
        for _ in 0..<totalCount {
            let randomIndex : Int = Int(arc4random_uniform(UInt32(count)))
            let randomElement : Element = tempArray.remove(at: randomIndex)
            shuffledArray.append(randomElement)
            count -= 1
        }
        return shuffledArray
    }

// Mutating shuffle
    mutating func shuffle() {
        let totalCount : Int = self.count
        var shuffledArray : Array = []
        var count : Int = totalCount
        var tempArray : Array = self
        for _ in 0..<totalCount {
            let randomIndex : Int = Int(arc4random_uniform(UInt32(count)))
            let randomElement : Element = tempArray.remove(at: randomIndex)
            shuffledArray.append(randomElement)
            count -= 1
        }
        self = shuffledArray
    }
}

Llamada aleatoria no mutante [Array] -> [Array]:

let array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

print(array.shuffled)

Esto se imprime arrayen un orden aleatorio.


Llamada de mutación aleatoria [Array] = [Array]:

var array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

array.shuffle() 
// The array has now been mutated and contains all of its initial 
// values, but in a randomized shuffled order

print(array) 

Esto se imprime arrayen su orden actual, que ya se ha barajado aleatoriamente.


Espero que esto funcione para todos, si tiene alguna pregunta, sugerencia o comentario, ¡no dude en preguntar!

Noah Wilder
fuente
0

En SWIFT 4

func createShuffledSequenceOfNumbers(max:UInt)->[UInt] {

    var array:[UInt]! = []
    var myArray:[UInt]! = []
    for i in 1...max {
        myArray.append(i)
    }
    for i in 1...max {
        array.append(i)
    }
    var tempArray:[Int]! = []
    for index in 0...(myArray.count - 1) {

        var isNotFinded:Bool = true
        while(isNotFinded){

            let randomNumber = arc4random_uniform(UInt32(myArray.count))
            let randomIndex = Int(randomNumber)

            if(!tempArray.contains(randomIndex)){
                tempArray.append(randomIndex)

                array[randomIndex] = myArray[index]
                isNotFinded = false
            }
        }
    }

    return array
}
Ali Khezri
fuente
0

Si desea utilizar la función de bucle Swift For simple, use esto ->

var arrayItems = ["A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "X9", "Y10", "Z11"]
var shuffledArray = [String]()

for i in 0..<arrayItems.count
{
    let randomObject = Int(arc4random_uniform(UInt32(items.count)))

    shuffledArray.append(items[randomObject])

    items.remove(at: randomObject)
}

print(shuffledArray)

Swift Array sufle usando la extensión ->

extension Array {
    // Order Randomize
    mutating func shuffle() {
        for _ in 0..<count {
            sort { (_,_) in arc4random() < arc4random() }
        }
    }
}
Rahul Singha Roy
fuente
0

A partir de swift 4.2 hay dos funciones útiles:

// shuffles the array in place
myArray.shuffle()

y

// generates a new array with shuffled elements of the old array
let newArray = myArray.shuffled()
lince rápido
fuente
-2

Aquí hay un código que se ejecuta en el patio de recreo. No necesitará importar Darwin en un proyecto real de Xcode.

import darwin

var a = [1,2,3,4,5,6,7]

func shuffle<ItemType>(item1: ItemType, item2: ItemType) -> Bool {
    return drand48() > 0.5
}

sort(a, shuffle)

println(a)
Dan Hixon
fuente
77
Esto proporciona una distribución no uniforme de los resultados. También será O (n log n), donde un shuffle de Fisher-Yates daría resultados distribuidos uniformemente en el tiempo O (n).
pjs
También drand48()da los mismos números pseudoaleatorios cada vez, a menos que establezca una semilla con me gustasrand48(Int(arc4random()))
Kametrixom
-3

Se detiene en "swap (& self [i], & self [j])" cuando actualizo la versión de xCode a 7.4 beta.
error fatal: no se admite el intercambio de una ubicación consigo mismo

Encontré la razón por la que i = j (la función de intercambio explotará)

Entonces agrego una condición como a continuación

if (i != j){
    swap(&list[i], &list[j])
}

YA! Esta bien para mi.

米米米
fuente
Esto parece ser un comentario sobre la respuesta de Chris , no una respuesta a la pregunta original.
Mogsdad