Wie mische ich ein Array in Swift?


305

Wie randomisiere oder mische ich die Elemente in einem Array in Swift? Zum Beispiel, wenn mein Array aus 52 Karten besteht, mag ich mische das Array , um das Deck zu mischen.


2
Dies ist nicht spezifisch für eine Sprache. Wenden Sie einfach einen beliebigen Mischalgorithmus an ...
Gabriele Petronella

8
@Mithrandir Das stimmt nicht. In Ruby würde man sich entscheiden array.shuffle. Sie müssen keine eigene Version implementieren. Ich denke, OP suchte nach etwas Ähnlichem.
Linus Oleander

1
Seien Sie jedoch vorsichtig, verwenden Sie nicht irgendeinen Shuffle-Algorithmus, um ein Kartenspiel zu mischen.
njzk2

Antworten:


627

Diese Antwort beschreibt, wie Sie mit einem schnellen und einheitlichen Algorithmus (Fisher-Yates) in Swift 4.2+ mischen und wie Sie dieselbe Funktion in den verschiedenen früheren Versionen von Swift hinzufügen. Die Benennung und das Verhalten für jede Swift-Version stimmen mit den mutierenden und nicht mutierenden Sortiermethoden für diese Version überein.

Swift 4.2+

shuffleund shuffledsind native ab Swift 4.2. Anwendungsbeispiel:

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 und 4.1

Diese Erweiterungen fügen shuffle()jeder veränderlichen Sammlung (Arrays und unsichere veränderbare Puffer) eine shuffled()Methode und jeder Sequenz eine Methode hinzu:

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

Gleiche Verwendung wie in den obigen Swift 4.2-Beispielen.


Swift 3

Diese Erweiterungen fügen shuffle()jeder veränderlichen Sammlung eine shuffled()Methode und jeder Sequenz eine Methode hinzu:

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

Gleiche Verwendung wie in den obigen Swift 4.2-Beispielen.


Swift 2

(veraltete Sprache: Sie können Swift 2.x nicht verwenden, um ab Juli 2018 auf iTunes Connect zu veröffentlichen.)

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

Verwendungszweck:

[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

(veraltete Sprache: Sie können Swift 1.x nicht verwenden, um ab Juli 2018 auf iTunes Connect zu veröffentlichen.)

shuffle als mutierende Array-Methode

Mit dieser Erweiterung können Sie eine veränderbare ArrayInstanz an Ort und Stelle mischen :

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 als nicht mutierende Array-Methode

Mit dieser Erweiterung können Sie eine gemischte Kopie einer ArrayInstanz abrufen :

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]

1
Wenn Sie die Funktionsversion in Swift 1.2 möchten, muss sie ein wenig aktualisiert werden, da sie nicht mehr vorhanden countElementsist. Der Ersatz countgibt jetzt a zurück, T.Index.Distancesodass die Einschränkung aktiviert sein muss C.Index.Distance == Int. Diese Version sollte funktionieren: gist.github.com/airspeedswift/03d07a9dc86fabdc370f
Fluggeschwindigkeit Velocity

2
Dies ist die eigentliche Ausgabe. Fisher-Yates sollte eine unverzerrte zufällige Permutation der Quelle zurückgeben, sodass kein bestimmtes Element verschoben werden muss. Es gibt eine Garantie dafür, dass sich kein Element mehr als einmal bewegt, aber manchmal erfolgt die "Verschiebung" auf denselben Index. Der einfachste Fall ist, darüber nachzudenken - [1, 2].shuffled()sollte das [2, 1]jedes Mal zurückkehren?
Nate Cook

1
Ich habe if count > 0oben in der Funktion des mutierenden Arrays hinzugefügt , um zu verhindern, dass ein "schwerwiegender Fehler: Bereich mit Ende <Start" kann nicht gebildet werden, wenn ein leeres Array übergeben wird.
Carl Smith

3
@ Jan: Ja, guard i != j else { continue }vor dem Tausch hinzufügen . Ich habe ein Radar eingereicht, aber das neue Verhalten ist beabsichtigt.
Nate Cook

3
shuffleInPlaceKann tatsächlich abstürzen, wenn die Sammlungsindizes nicht bei Null beginnen, z. B. für ein Array-Slice. for i in 0..<count - 1 sollte sein for i in startIndex ..< endIndex - 1(und dann wird die Konvertierung zu Swift 3 fast trivial).
Martin R

131

Bearbeiten: Wie in anderen Antworten erwähnt, fügt Swift 4.2 der Standardbibliothek schließlich eine Zufallszahlengenerierung hinzu, einschließlich Array-Shuffling.

Die GKRandom/ GKRandomDistributionsuite in GameplayKit kann jedoch mit dem neuen RandomNumberGeneratorProtokoll weiterhin nützlich sein. Wenn Sie den GameplayKit-RNGs Erweiterungen hinzufügen, um sie an das neue Standardbibliotheksprotokoll anzupassen, erhalten Sie auf einfache Weise:

  • sendbare RNGs (die eine "zufällige" Sequenz reproduzieren können, wenn sie zum Testen benötigt werden)
  • RNGs, die Robustheit für Geschwindigkeit opfern
  • RNGs, die ungleichmäßige Verteilungen erzeugen

... und nutzen Sie trotzdem die netten neuen "nativen" Zufalls-APIs in Swift.

Der Rest dieser Antwort betrifft solche RNGs und / oder ihre Verwendung in älteren Swift-Compilern.


Hier gibt es bereits einige gute Antworten sowie einige gute Beispiele dafür, warum das Schreiben eines eigenen Shuffle fehleranfällig sein kann, wenn Sie nicht vorsichtig sind.

In iOS 9, macOS 10.11 und tvOS 9 (oder höher) müssen Sie keine eigenen schreiben. Es gibt eine effiziente, korrekte Implementierung von Fisher-Yates in GameplayKit (das trotz des Namens nicht nur für Spiele gedacht ist).

Wenn Sie nur ein einzigartiges Shuffle möchten:

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

Wenn Sie in der Lage sein möchten, ein Mischen oder eine Reihe von Mischen zu replizieren, wählen Sie eine bestimmte zufällige Quelle aus und setzen Sie sie. z.B

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

In iOS 10 / macOS 10.12 / tvOS 10 gibt es auch eine praktische Syntax zum Mischen über eine Erweiterung NSArray. Das ist natürlich etwas umständlich, wenn Sie einen Swift verwenden Array(und er verliert seinen Elementtyp, wenn Sie zu Swift zurückkehren):

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

Aber es ist ziemlich einfach, einen typerhaltenden Swift-Wrapper dafür zu erstellen:

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

6
Ich frage mich, welche anderen hilfreichen Dienstprogramme in GameplayKit enthalten sind, die ich noch nie erforscht habe!
Richard Venable

6
Diagrammsuche, Baumsuche, Regelsysteme ... viele Dinge , die sowohl im Spieldesign als auch auf andere Weise hilfreich sind.
Rickster

5
In Swift 3 / iOS 10 wurde dies geändert in:let shuffled = lcg.arrayByShufflingObjects(in: array)
Evan Pon

30

In Swift 2.0 kann GameplayKit Abhilfe schaffen! (unterstützt von iOS9 oder höher)

import GameplayKit

func shuffle() {
    array = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(array)
}

5
GameplayKit zu importieren, nur um ein gemischtes Array zu erhalten, klingt nicht nach einer großartigen Idee
Lope

3
Warum? Es ist Teil des Systems und wird nicht zur Binärdatei hinzugefügt.
Abizern

3
Sie können den Import auch auf einfach beschränkenimport GameplayKit.GKRandomSource
JRG-Developer

26

Hier ist etwas möglicherweise etwas kürzer:

sorted(a) {_, _ in arc4random() % 2 == 0}

1
@moby Die sortFunktion benötigt einen Abschluss, um Elemente zu bestellen. Dieser Abschluss akzeptiert zwei Parameter (elem1, elem2) und muss true zurückgeben, wenn der erste Wert vor dem zweiten Wert erscheinen soll, andernfalls false. Wenn wir stattdessen einen zufälligen Booleschen Wert zurückgeben ... dann verwechseln wir einfach das Ganze :)
Jean Le Moignan

2
Gibt es hier einen Mathematiker, der dies bestätigt oder widerlegt?
Jean Le Moignan

9
Wie pjs als Antwort auf eine andere sehr ähnliche Antwort hervorhob, wird dies keine gleichmäßige Verteilung der Ergebnisse erzeugen. Verwenden Sie Fisher-Yates Shuffle wie in der Antwort von Nate Cook gezeigt.
Rob

1
Dies ist ein cleverer Trick, aber in Bezug auf die Qualität des Shuffle miserabel. Zum einen sollte dieser Verschluss verwendet werden arc4random_uniform(), da er derzeit der Modulo-Vorspannung unterliegt. Zweitens hängt die Ausgabe sehr stark vom Sortieralgorithmus ab (der uns ohne Blick auf die Quelle nicht bekannt ist).
Alexander - Reinstate Monica

1
Wenn man diesen einfacheren Ansatz fortsetzt, scheint dies recht gut zu funktionieren: collection.sorted { _,_ in arc4random_uniform(1) == 0 }
Markiv

7

Mit dem Algorithmus von Nate wollte ich sehen, wie dies mit Swift 2 und Protokollerweiterungen aussehen würde.

Das habe ich mir ausgedacht.

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

Jetzt kann jeder MutableCollectionTypediese Methoden verwenden, vorausgesetzt, er verwendet IntalsIndex


6

In meinem Fall hatte ich einige Probleme beim Austauschen von Objekten in Array. Dann kratzte ich mich am Kopf und erfand das Rad neu.

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

}

5

Dies ist eine Version von Nates Implementierung des Fisher-Yates-Shuffle für 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
    }
}

Die Änderungen sind:

  • Die Einschränkung Indices.Iterator.Element == Indexist jetzt Teil des CollectionProtokolls und muss der Erweiterung nicht mehr auferlegt werden.
  • Der Austausch von Elementen muss durch Aufrufen swapAt()der Sammlung erfolgen, vergleiche SE-0173 HinzufügenMutableCollection.swapAt(_:_:) .
  • Elementist ein Alias ​​für Iterator.Element.

3

Das benutze ich:

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
}

3

Swift 4 Mische die Elemente eines Arrays in einer for-Schleife, wobei i das Mischungsverhältnis ist

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

Oder mit der Erweiterung 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
        }
    }
}

2

Swift 3-Lösung, folgende Antwort von @Nate Cook: (Arbeiten, wenn der Index mit 0 beginnt, siehe Kommentare unten)

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

1
Dies kann abstürzen, wenn die Sammlungsindizes bei 0 beginnen, z. B. für ein Array-Slice. Versuche var a = [1, 2, 3, 4, 5, 6][3..<6]; a.shuffleInPlace()mehrmals zu laufen . - Eine korrekte Lösung finden Sie unter stackoverflow.com/a/37843901/1187415 .
Martin R

2

So wird es auf einfachste Weise gemacht. import Gamplaykitzu Ihrem VC und verwenden Sie den folgenden Code. Getestet in Xcode 8.

 import GameplayKit

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

 override func viewDidLoad() {
    super.viewDidLoad()

    print(array.shuffled())  
}

Wenn Sie einen gemischten String aus einem Array erhalten möchten, können Sie den folgenden Code verwenden.

func suffleString() {

    let ShuffleArray = array.shuffled()

    suffleString.text = ShuffleArray.first as? String

    print(suffleString.text!)

}

2

Wenn Sie mit Swift 3 ein Array an Ort und Stelle mischen oder ein neues gemischtes Array aus einem Array abrufen möchten, AnyIteratorkann dies hilfreich sein. Die Idee ist, ein Array von Indizes aus Ihrem Array zu erstellen, diese Indizes mit einer AnyIteratorInstanz und swap(_:_:)Funktion zu mischen und jedes Element dieser AnyIteratorInstanz dem entsprechenden Element des Arrays zuzuordnen .


Der folgende Spielplatzcode zeigt, wie es funktioniert:

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

Sie können den vorherigen Code umgestalten und eine shuffled()Funktion in einer ArrayErweiterung erstellen , um ein neues gemischtes Array aus einem Array zu erhalten:

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

}

Verwendungszweck:

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: []

Alternativ zum vorherigen Code können Sie eine shuffle()Funktion in einer ArrayErweiterung erstellen , um ein Array an Ort und Stelle zu mischen:

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

}

Verwendungszweck:

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

1

Sie können auch die generische swapFunktion verwenden und die genannten Fisher-Yates implementieren:

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

oder weniger ausführlich:

for idx in 0..<steps.count {
  swap(&steps[idx], &steps[Int(arc4random_uniform(UInt32(idx)))])
}

2
Dies leidet zumindest an einem schwerwiegenden Fehler , der durch einen hier beschriebenen Fehler verursacht wird, bei dem ein Wert immer von seiner ursprünglichen Position ausgetauscht wird. Dies wird behoben mit let rnd = Int(arc4random_uniform(UInt32(idx + 1))). Außerdem iterieren Sie im Geschäftsjahr im Allgemeinen von arr.count - 1unten nach unten 1(oder wenn Sie von 0bis iterieren arr.count - 1, wählen Sie einen Index aus, wie Nate in der akzeptierten Antwort zeigt). Siehe Abschnitt Moderner Algorithmus in der Fisher-Yates-Diskussion.
Rob

1

funktioniert !!. Organismen ist das Array zu mischen.

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


0

So mischen Sie ein Array mit einem Startwert in 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])
        }
    }
}

0
let shuffl = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: arrayObject)

0

Das benutze ich:

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]

0

Einfaches Beispiel:

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]

0

Working Array Extension (mutierend und nicht mutierend)

Swift 4.1 / Xcode 9

Die Top-Antwort ist veraltet, daher habe ich es mir zur Aufgabe gemacht, eine eigene Erweiterung zu erstellen, um ein Array in der neuesten Version von Swift, Swift 4.1 (Xcode 9), zu mischen:

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

Nicht mutierendes Shuffle nennen [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)

Dies wird arrayin zufälliger Reihenfolge gedruckt .


Mutating Shuffle nennen [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) 

Dies wird arrayin der aktuellen Reihenfolge gedruckt , die bereits zufällig gemischt wurde.


Ich hoffe, dass dies für alle funktioniert. Wenn Sie Fragen, Anregungen oder Kommentare haben, können Sie diese gerne stellen!


0

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

0

Wenn Sie eine einfache Swift For-Schleifenfunktion verwenden möchten, verwenden Sie diese ->

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 genügt mit der Erweiterung ->

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

0

Ab Swift 4.2 gibt es zwei praktische Funktionen:

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

und

// generates a new array with shuffled elements of the old array
let newArray = myArray.shuffled()

-2

Hier ist ein Code, der auf dem Spielplatz ausgeführt wird. Sie müssen Darwin nicht in ein aktuelles Xcode-Projekt importieren.

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)

7
Dies ergibt eine ungleichmäßige Verteilung der Ergebnisse. Es wird auch O (n log n) sein, wobei ein Fisher-Yates-Shuffle in O (n) -Zeit gleichmäßig verteilte Ergebnisse liefern würde.
pjs

Auch drand48()gibt die gleiche Pseudo - Zufallszahlen jedes Mal, wenn Sie einen Samen mit wie eingestelltsrand48(Int(arc4random()))
Kametrixom

-3

Es stoppt bei "Swap (& self [i], & self [j])", wenn ich die xCode-Version auf 7.4 Beta aktualisiere.
Schwerwiegender Fehler: Das Austauschen eines Standorts mit sich selbst wird nicht unterstützt

Ich habe den Grund gefunden, dass i = j (Funktion des Swaps wird explodieren)

Also füge ich eine Bedingung wie unten hinzu

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

YA! Für mich ist das in Ordnung.


Dies scheint ein Kommentar zu Chris 'Antwort zu sein , keine Antwort auf die ursprüngliche Frage.
Mogsdad
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.