Bagaimana cara mengocok array di Swift?


305

Bagaimana cara mengacak atau mengacak elemen dalam array di Swift? Sebagai contoh, jika array saya terdiri dari 52 kartu remi, saya ingin mengocok array untuk mengocok deck.


2
ini tidak spesifik untuk bahasa apa pun. Cukup terapkan algoritma pengacakan apa pun ...
Gabriele Petronella

8
@Mithrandir Itu tidak benar. Di Ruby satu akan pergi untuk array.shuffle. Tidak perlu menerapkan versi Anda sendiri. Saya kira OP sedang mencari sesuatu yang serupa.
Linus Oleander

1
berhati-hatilah, jangan gunakan sembarang algoritma acak untuk mengocok setumpuk kartu.
njzk2

Jawaban:


627

Jawaban ini merinci cara mengocok dengan algoritma cepat dan seragam (Fisher-Yates) di Swift 4.2+ dan cara menambahkan fitur yang sama di berbagai versi Swift sebelumnya. Penamaan dan perilaku untuk setiap versi Swift cocok dengan metode penyortiran yang bermutasi dan nonmutasi untuk versi itu.

Swift 4.2+

shuffledan shuffledasli mulai Swift 4.2. Contoh penggunaan:

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

Ekstensi ini menambahkan shuffle()metode ke koleksi yang dapat diubah (array dan buffer yang tidak bisa diubah) dan shuffled()metode untuk urutan apa pun:

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

Penggunaan yang sama seperti pada contoh Swift 4.2 di atas.


Cepat 3

Ekstensi ini menambahkan shuffle()metode ke koleksi yang dapat diubah dan shuffled()metode ke urutan apa pun:

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

Penggunaan yang sama seperti pada contoh Swift 4.2 di atas.


Cepat 2

(bahasa usang: Anda tidak dapat menggunakan Swift 2.x untuk menerbitkan di iTunes Connect mulai Juli 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
    }
}

Pemakaian:

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

Cepat 1.2

(bahasa usang: Anda tidak dapat menggunakan Swift 1.x untuk menerbitkan di iTunes Connect mulai Juli 2018)

shuffle sebagai metode array bermutasi

Ekstensi ini akan memungkinkan Anda mengocok Arrayinstance yang bisa berubah di tempat:

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 sebagai metode array yang tidak bermutasi

Ekstensi ini akan memungkinkan Anda mengambil salinan Arraycontoh yang dikocok :

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
Jika Anda menginginkan versi fungsi di Swift 1.2, perlu sedikit pembaruan seperti yang countElementssudah hilang, dan itu penggantian count,, sekarang mengembalikan T.Index.Distancesehingga kendala perlu dihidupkan C.Index.Distance == Int. Versi ini akan berfungsi: gist.github.com/airspeedswift/03d07a9dc86fabdc370f
Airspeed Velocity

2
Itu adalah hasil aktual — Fisher-Yates harus mengembalikan permutasi acak yang tidak bias dari sumber, jadi tidak ada persyaratan bahwa elemen tertentu harus bergerak. Ada adalah jaminan bahwa tidak ada unsur bergerak lebih dari sekali, tapi kadang-kadang "bergerak" adalah untuk indeks yang sama. Kasus paling sederhana adalah memikirkan — apakah [1, 2].shuffled()itu akan kembali [2, 1]setiap waktu?
Nate Cook

1
Saya menambahkan if count > 0di bagian atas fungsi array yang bermutasi, untuk mencegah menerima "kesalahan fatal: Tidak dapat membentuk Rentang dengan akhir <mulai" ketika dilewatkan array kosong.
Carl Smith

3
@ Jan: Ya, tambahkan guard i != j else { continue }sebelum swap. Saya mengajukan radar, tetapi perilaku baru itu disengaja.
Nate Cook

3
Sebenarnya shuffleInPlacebisa crash jika indeks koleksi tidak dimulai dari nol, misalnya untuk slice array. for i in 0..<count - 1 seharusnya for i in startIndex ..< endIndex - 1(dan kemudian konversi ke Swift 3 menjadi hampir sepele).
Martin R

131

Sunting: Sebagaimana dicatat dalam jawaban lain, Swift 4.2 akhirnya menambahkan pembuatan angka acak ke pustaka standar, lengkap dengan pengocokan array.

Namun, GKRandom/ GKRandomDistributionsuite di GameplayKit masih dapat bermanfaat dengan RandomNumberGeneratorprotokol baru - jika Anda menambahkan ekstensi ke GameplayKit RNGs agar sesuai dengan protokol perpustakaan standar baru, Anda dapat dengan mudah mendapatkan:

  • RNG yang dapat dikirim (yang dapat mereproduksi urutan "acak" saat diperlukan untuk pengujian)
  • RNG yang mengorbankan ketahanan untuk kecepatan
  • RNG yang menghasilkan distribusi tidak seragam

... dan masih menggunakan API acak "asli" baru yang bagus di Swift.

Sisa jawaban ini menyangkut RNG dan / atau penggunaannya dalam kompiler Swift yang lebih lama.


Sudah ada beberapa jawaban bagus di sini, serta beberapa ilustrasi bagus mengapa menulis shuffle Anda sendiri bisa rawan kesalahan jika Anda tidak hati-hati.

Di iOS 9, macOS 10.11, dan tvOS 9 (atau lebih baru), Anda tidak harus menulis sendiri. Ada implementasi Fisher-Yates yang efisien dan benar di GameplayKit (yang, terlepas dari namanya, tidak hanya untuk game).

Jika Anda hanya ingin pengocokan unik:

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

Jika Anda ingin dapat mereplikasi shuffle atau serangkaian shuffles, pilih dan buang sumber acak tertentu; misalnya

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

Di iOS 10 / macOS 10.12 / tvOS 10, ada juga sintaksis kenyamanan untuk mengacak melalui ekstensi aktif NSArray. Tentu saja, itu sedikit rumit ketika Anda menggunakan Swift Array(dan kehilangan tipe elemennya saat kembali ke Swift):

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

Tapi cukup mudah untuk membuat pembungkus Swift tipe pengawet untuk itu:

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
Buat saya bertanya-tanya utilitas apa yang bisa ditemukan di GameplayKit yang belum pernah saya jelajahi!
Richard Venable

6
Pencarian grafik, pencarian pohon, sistem aturan ... banyak hal yang bermanfaat baik dalam desain game maupun sebaliknya.
rickster

5
Di Swift 3 / iOS 10, ini telah diubah menjadi:let shuffled = lcg.arrayByShufflingObjects(in: array)
Evan Pon

30

Di Swift 2.0 , GameplayKit bisa menyelamatkan! (didukung oleh iOS9 atau yang lebih baru)

import GameplayKit

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

5
mengimpor GameplayKit hanya untuk mendapatkan array yang dikocok tidak terdengar seperti ide yang bagus
Lope

3
Mengapa? Itu bagian dari sistem, tidak menambah biner.
Abizern

3
Anda juga dapat mengatur impor hanyaimport GameplayKit.GKRandomSource
JRG-Developer

26

Berikut ini sesuatu yang mungkin sedikit lebih pendek:

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

1
@moby sortFungsi ini membutuhkan penutupan untuk memesan elemen. Penutupan ini mengambil dua parameter (elem1, elem2) dan harus mengembalikan true jika nilai pertama harus muncul sebelum nilai kedua, dan false jika tidak. Jika kita mengembalikan boolean acak sebagai gantinya ... maka kita hanya mencampur semuanya :)
Jean Le Moignan

2
Adakah ahli matematika di sini untuk mengonfirmasi atau membantah?
Jean Le Moignan

9
Seperti yang ditunjukkan oleh pj dalam menanggapi jawaban lain yang sangat mirip, ini tidak akan menghasilkan distribusi hasil yang seragam. Gunakan Shuffle Fisher-Yates seperti yang ditunjukkan dalam jawaban Nate Cook.
Rob

1
Ini adalah trik yang cerdas, tetapi buruk dalam hal kualitas shuffle. Untuk satu, penutupan ini harus digunakan arc4random_uniform(), karena saat ini tunduk pada bias modulo. Kedua, output sangat tergantung pada algoritma pengurutan (yang tidak kita ketahui tanpa melihat sumbernya).
Alexander - Reinstate Monica

1
Melanjutkan dengan pendekatan yang lebih sederhana ini, ini tampaknya bekerja dengan cukup baik: collection.sorted { _,_ in arc4random_uniform(1) == 0 }
markiv

7

Mengambil algoritma Nate saya ingin melihat bagaimana ini akan terlihat dengan Swift 2 dan ekstensi protokol.

Inilah yang saya pikirkan.

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

Sekarang, siapa pun MutableCollectionTypedapat menggunakan metode ini mengingat itu digunakan IntsebagaiIndex


6

Dalam kasus saya, saya punya beberapa masalah dengan menukar objek di Array. Lalu aku menggaruk kepalaku dan pergi untuk menemukan kembali rodanya.

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

Ini adalah versi implementasi Nate dari shuffle Fisher-Yates untuk 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
    }
}

Perubahannya adalah:

  • Batasan Indices.Iterator.Element == Indexsekarang menjadi bagian dari Collectionprotokol, dan tidak perlu dikenakan pada ekstensi lagi.
  • Bertukar elemen harus dilakukan dengan memanggil swapAt()koleksi, bandingkan SE-0173 TambahMutableCollection.swapAt(_:_:) .
  • Elementadalah alias untuk Iterator.Element.

3

Inilah yang saya gunakan:

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 Kocok elemen-elemen array dalam for for loop di mana i adalah rasio pencampuran

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

Atau dengan ekstensi 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

Solusi Swift 3, berikut @Nate Cook menjawab: (berfungsi jika indeks dimulai dengan 0, lihat komentar di bawah)

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
Ini bisa macet jika indeks koleksi mulai dari 0, misalnya untuk slice array. Coba jalankan var a = [1, 2, 3, 4, 5, 6][3..<6]; a.shuffleInPlace()beberapa kali. - Lihat stackoverflow.com/a/37843901/1187415 untuk solusi yang benar.
Martin R

2

Ini adalah bagaimana ini dilakukan dengan cara yang paling sederhana. import Gamplaykitke VC Anda dan gunakan kode di bawah ini. Diuji dalam Xcode 8.

 import GameplayKit

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

 override func viewDidLoad() {
    super.viewDidLoad()

    print(array.shuffled())  
}

Jika Anda ingin mendapatkan String yang diacak dari Array, Anda dapat menggunakan kode di bawah ini ..

func suffleString() {

    let ShuffleArray = array.shuffled()

    suffleString.text = ShuffleArray.first as? String

    print(suffleString.text!)

}

2

Dengan Swift 3, jika Anda ingin mengocok array di tempatnya atau mendapatkan array yang diacak dari array, AnyIteratordapat membantu Anda. Idenya adalah untuk membuat array indeks dari array Anda, untuk mengocok indeks tersebut dengan AnyIteratorinstance dan swap(_:_:)fungsi dan untuk memetakan setiap elemen dari AnyIteratorinstance ini dengan elemen yang sesuai array.


Kode Playground berikut menunjukkan cara kerjanya:

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

Anda bisa memperbaiki kode sebelumnya dan membuat shuffled()fungsi di dalam Arrayekstensi untuk mendapatkan array yang diacak dari array:

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

}

Pemakaian:

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

Sebagai alternatif dari kode sebelumnya, Anda dapat membuat shuffle()fungsi di dalam Arrayekstensi untuk mengocok array di tempat:

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

}

Pemakaian:

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

1

Anda dapat menggunakan swapfungsi generik juga dan mengimplementasikan Fisher-Yates yang disebutkan:

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

atau kurang verbose:

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

2
Ini menderita, paling tidak, kesalahan serius oleh satu kesalahan yang dijelaskan di sini di mana nilai selalu diganti dari posisi aslinya. Ini diperbaiki dengan let rnd = Int(arc4random_uniform(UInt32(idx + 1))). Juga, di TA, Anda biasanya beralih dari arr.count - 1bawah ke 1(atau jika Anda beralih dari 0ke arr.count - 1, Anda memilih indeks seperti Nate menunjukkan dalam jawaban yang diterima). Lihat bagian Algoritma Modern dari diskusi Fisher-Yates.
Rob

1

berhasil !!. organisme adalah array untuk diacak.

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

Ini adalah cara mengocok satu array dengan seed di 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

Inilah yang saya gunakan:

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

Contoh sederhana:

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

Extension Array yang Berfungsi (bermutasi & tidak bermutasi)

Swift 4.1 / Xcode 9

Jawaban teratas sudah usang, jadi saya mengambil sendiri untuk membuat ekstensi sendiri untuk mengocok array dalam versi terbaru 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
    }
}

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

Ini mencetak arraydalam urutan acak.


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

Ini mencetak arraydalam urutan saat ini, yang telah dikocok secara acak.


Berharap ini bekerja untuk semua orang, jika Anda memiliki pertanyaan, saran, atau komentar, jangan ragu untuk bertanya!


0

Dalam 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

Jika Anda ingin menggunakan fungsi Swift For loop yang sederhana gunakan ini ->

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)

Array Swift suffle menggunakan ekstensi ->

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

0

Pada swift 4.2 ada dua fungsi praktis:

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

dan

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

-2

Berikut beberapa kode yang berjalan di taman bermain. Anda tidak perlu mengimpor Darwin dalam proyek Xcode yang sebenarnya.

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
Ini memberikan distribusi hasil yang tidak seragam. Ini juga akan menjadi O (n log n), di mana shuffle Fisher-Yates akan memberikan hasil yang terdistribusi secara merata dalam waktu O (n).
pjs

Juga drand48()memberikan angka acak semu yang sama setiap kali, kecuali jika Anda menetapkan seed dengan likesrand48(Int(arc4random()))
Kametrixom

-3

Itu berhenti di "swap (& self [i], & self [j])" ketika saya meningkatkan versi xCode ke 7.4 beta.
kesalahan fatal: menukar lokasi dengan dirinya sendiri tidak didukung

Saya menemukan alasan bahwa i = j (fungsi swap akan meledak)

Jadi saya tambahkan syarat seperti di bawah ini

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

YA! Tidak masalah bagi saya.


Tampaknya ini merupakan komentar atas jawaban Chris , bukan jawaban untuk pertanyaan awal.
Mogsdad
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.