Swift'te bir diziyi nasıl karıştırabilirim?


305

Swift içindeki bir dizideki öğeleri nasıl rastgele seçerim veya karıştırırım? Örneğin, dizim 52 oyun kartından oluşuyorsa , desteyi karıştırmak için diziyi karıştırmak istiyorum .


2
bu herhangi bir dile özgü değildir. Sadece herhangi bir karıştırma algoritması uygulayın ...
Gabriele Petronella

8
@Mithrandir Bu doğru değil. Ruby'de biri giderdi array.shuffle. Kendi sürümünüzü uygulamaya gerek yoktur. Sanırım OP benzer bir şey arıyordu.
Linus Oleander

1
dikkatli olun, bir deste desteyi karıştırmak için herhangi bir karıştırma algoritması kullanmayın.
njzk2

Yanıtlar:


627

Bu yanıt, Swift 4.2 ve sonraki sürümlerinde hızlı ve tekdüze bir algoritma (Fisher-Yates) ile nasıl karıştırılacağını ve Swift'in önceki çeşitli sürümlerinde aynı özelliğin nasıl ekleneceğini detaylandırıyor. Her Swift sürümünün adlandırma ve davranışı, söz konusu sürüm için mutasyona uğrayan ve değiştirmeyen sıralama yöntemleriyle eşleşir.

Hızlı 4.2+

shuffleve shuffledSwift 4.2'den başlayan yereldir. Örnek kullanım:

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

Bu uzantılar shuffle()herhangi bir değişken koleksiyona bir yöntem (diziler ve güvenli olmayan değiştirilebilir tamponlar) ve shuffled()herhangi bir diziye bir yöntem ekler :

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

Yukarıdaki Swift 4.2 örnekleriyle aynı kullanım.


Hızlı 3

Bu uzantılar shuffle()herhangi bir değiştirilebilir koleksiyona bir shuffled()yöntem ve herhangi bir diziye bir yöntem ekler :

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

Yukarıdaki Swift 4.2 örnekleriyle aynı kullanım.


Hızlı 2

(eski dil: Temmuz 2.20'de iTunes Connect'te yayınlamak için Swift 2.x'i kullanamazsınız)

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

Kullanımı:

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

Hızlı 1.2

(eski dil: Temmuz 2018'den itibaren iTunes Connect'te yayınlamak için Swift 1.x'i kullanamazsınız)

shuffle bir mutasyon dizisi yöntemi olarak

Bu uzantı, değiştirilebilir bir Arrayörneği yerinde karıştırmanıza olanak tanır :

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 değişmeyen dizi yöntemi olarak

Bu uzantı, bir Arrayörneğin karıştırılmış bir kopyasını almanıza olanak tanır :

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
Swift 1.2'deki işlev sürümünü istemeniz durumunda countElements, gittiği gibi biraz güncellenmesi gerekiyor ve yerine countgeçiyor, şimdi bir T.Index.Distancekısıtlama olması için bir döndürüyor C.Index.Distance == Int. Bu sürüm çalışmalıdır: gist.github.com/airspeedswift/03d07a9dc86fabdc370f
Hava Hızı Hızı

2
Bunlar gerçek çıktıdır - Fisher-Yates kaynağın tarafsız bir rastgele permütasyonu döndürmelidir, bu nedenle belirli bir elemanın hareket etmesi gerekmez. Orada olan bir garanti hiçbir eleman hamle kereden fazla, fakat bazen "hareket" aynı indeksi etmektir. En basit durum düşünmek [1, 2].shuffled()-bu [2, 1]her seferinde geri dönmeli mi?
Nate Cook

1
Ben if count > 0"ölümcül hata: boş bir dizi geçtiğinde bitiş <start" ile aralığı oluşturamıyorum önlemek için, mutasyon dizisi işlevinin üstüne ekledi .
Carl Smith

3
@Jan: Evet, takastan guard i != j else { continue }önce ekleyin . Bir radar açtım, ama yeni davranış kasıtlı.
Nate Cook

3
Aslında shuffleInPlace, toplama dizinleri sıfırdan başlamazsa, örneğin bir dizi dilimi için çökebilir. for i in 0..<count - 1 olmalıdır for i in startIndex ..< endIndex - 1(ve sonra Swift 3'e dönüşüm neredeyse önemsiz hale gelir).
Martin R

131

Düzenleme: Diğer cevaplarda belirtildiği gibi, Swift 4.2 nihayet dizi karıştırma ile tam standart kütüphaneye rastgele sayı oluşturma ekler.

Bununla birlikte, GameplayKit'teki GKRandom/ GKRandomDistributionsuite yine de yeni RandomNumberGeneratorprotokolle faydalı olabilir - yeni standart kütüphane protokolüne uymak için GameplayKit RNG'lerine uzantılar eklerseniz, şunları kolayca elde edebilirsiniz:

  • güvenilir RNG'ler (test için gerektiğinde "rastgele" bir sekans üretebilir)
  • Hız için sağlamlığı feda eden RNG'ler
  • Düzgün olmayan dağılımlar üreten RNG'ler

... ve yine de Swift'teki yeni güzel "yerli" rastgele API'leri kullanıyor.

Bu cevabın geri kalanı bu tür RNG'ler ve / veya eski Swift derleyicilerinde kullanımları ile ilgilidir.


Burada zaten bazı iyi cevaplar var ve dikkatli değilseniz kendi shuffle'ınızı yazmanın neden hataya açık olabileceğine dair bazı iyi çizimler var.

İOS 9, macOS 10.11 ve tvOS 9'da (veya daha yenisinde) kendiniz yazmak zorunda değilsiniz. Orada Fisher-Yates verimli, doğru uygulama (adı rağmen, sadece oyunlar için ise,) GameplayKit içinde.

Sadece benzersiz bir shuffle istiyorsanız:

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

Bir karıştırmayı veya bir dizi karıştırmayı çoğaltmak istiyorsanız, belirli bir rastgele kaynak seçin ve tohumlayın; Örneğin

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

İOS 10 / macOS 10.12 / tvOS 10'da, bir uzantı üzerinden karıştırma için bir kolaylık sözdizimi de vardır NSArray. Tabii ki, bir Swift kullanırken bu biraz hantal Array(ve Swift'e geri döndüğünde öğe türünü kaybediyor):

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

Ancak bunun için bir tür koruyucu Swift sarmalayıcı yapmak oldukça kolaydır:

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
GameplayKit'te hiç keşfetmediğim diğer yardımcı programların neler olabileceğini merak ettiriyor!
Richard Venable

6
Grafik araması, ağaç araması, kural sistemleri ... hem oyun tasarımında hem de diğer durumlarda yardımcı olan birçok şey .
rickster

5
Swift 3 / iOS 10'da, bu şu şekilde değiştirildi:let shuffled = lcg.arrayByShufflingObjects(in: array)
Evan Pon

30

In Swift 2.0 , GameplayKit kurtarmaya gelebilir! ( iOS9 veya üstü tarafından desteklenir )

import GameplayKit

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

5
karıştırılmış dizi almak için GameplayKit'i içe aktarmak harika bir fikir gibi gelmiyor
Lope

3
Neden? Sistemin bir parçası, ikiliye eklenmiyor.
Abizern

3
Ayrıca içe import GameplayKit.GKRandomSource
aktarmayı

26

Muhtemelen biraz daha kısa bir şey:

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

1
@moby İşlevin, sortöğeleri sipariş etmek için kapatılması gerekiyor. Bu kapatma iki parametre alır (elem1, elem2) ve eğer ilk değer ikinci değerden önce görünecekse true, aksi halde false döndürmelidir. Bunun yerine rastgele bir boole döndürürsek ... o zaman her şeyi karıştırırız :)
Jean Le Moignan

2
Onaylamak veya çürütmek için burada bir matematikçi var mı?
Jean Le Moignan

9
Pijama başka çok benzer bir cevap yanıt olarak belirttiği gibi, bu olacak değil sonuçların üniform dağılımını oluşturur. Fisher-Yates Shuffle'ı Nate Cook'un cevabında gösterildiği gibi kullanın .
Rob

1
Bu akıllıca bir hile, ancak shuffle kalitesi açısından uçsuz bucaksız. Birincisi, arc4random_uniform()şu anda modulo önyargılarına maruz kaldığı için bu kapatma kullanmalıdır . İkincisi, çıktı çok güçlü bir şekilde sıralama algoritmasına (kaynağa bakmadan bizim bilmediğimiz) bağlıdır.
Alexander - Monica'yı eski

1
Bu daha basit yaklaşıma devam ederek, bu oldukça güzel çalışıyor gibi görünüyor: collection.sorted { _,_ in arc4random_uniform(1) == 0 }
markiv

7

Alarak Nate'in algoritması bu Swift 2 ve protokol uzantıları ile nasıl görüneceğini görmek istedi.

Ben de bunu buldum.

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

Şimdi, herhangi MutableCollectionTypebiri bu yöntemleri IntbirIndex


6

Benim durumumda, Array'da nesneleri değiştirirken bazı sorunlar yaşadım. Sonra başımı kaşıdım ve tekerleği yeniden keşfetmeye gittim.

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

Bu Nate'in Swift 4 için Fisher-Yates shuffle (Xcode 9) uygulamasını uygulamasının bir sürümüdür .

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

Değişiklikler:

  • Kısıtlama Indices.Iterator.Element == Indexartık Collectionprotokolün bir parçasıdır ve artık uzantıya dayatılmasına gerek yoktur.
  • Değiş tokuş elemanlarının swapAt()koleksiyonu arayarak yapılması gerekir , SE-0173 Ekle'yiMutableCollection.swapAt(_:_:) karşılaştırın .
  • Elementiçin bir takma addır Iterator.Element.

3

Ne kullanıyorum:

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 i'nin karıştırma oranının olduğu bir for döngüsünde bir dizinin öğelerini karıştır

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

Veya Int uzantılı

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 çözümü, @Nate Cook cevabını takip ederek: (indeks 0 ile başlıyorsa çalışın, aşağıdaki yorumlara bakı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])
        }
    }
}

1
Toplama endeksleri 0'dan başlarsa, örneğin bir dizi dilimi için bu durum kilitlenebilir. var a = [1, 2, 3, 4, 5, 6][3..<6]; a.shuffleInPlace()Birkaç kez koşmaya çalışın . - Doğru çözüm için stackoverflow.com/a/37843901/1187415 adresine bakın .
Martin R

2

Bu en basit şekilde yapılır. import Gamplaykitve aşağıdaki kodu kullanın. Xcode 8'de test edilmiştir.

 import GameplayKit

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

 override func viewDidLoad() {
    super.viewDidLoad()

    print(array.shuffled())  
}

Bir Diziden karıştırılmış bir String almak istiyorsanız aşağıdaki kodu kullanabilirsiniz ..

func suffleString() {

    let ShuffleArray = array.shuffled()

    suffleString.text = ShuffleArray.first as? String

    print(suffleString.text!)

}

2

Swift 3 ile, bir diziyi yerinde karıştırmak veya bir diziden yeni bir karıştırılmış dizi almak AnyIteratoristiyorsanız , size yardımcı olabilir. Buradaki fikir dizinizden bir dizi dizin oluşturmak, bu dizinleri bir AnyIteratorörnek ve swap(_:_:)işlevle karıştırmak ve bu AnyIteratorörneğin her bir öğesini dizinin karşılık gelen öğesiyle eşlemektir.


Aşağıdaki Oyun Alanı kodu nasıl çalıştığını gösterir:

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

Bir diziden yeni bir karışık dizi elde etmek için önceki kodu yeniden düzenleyebilir ve shuffled()bir Arrayuzantı içinde bir işlev oluşturabilirsiniz :

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

}

Kullanımı:

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

Önceki koda alternatif olarak, bir diziyi yerinde karıştırmak için shuffle()bir Arrayuzantı içinde bir işlev oluşturabilirsiniz :

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

}

Kullanımı:

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

1

Jenerik swapişlevi de kullanabilir ve bahsedilen Fisher-Yates'i uygulayabilirsiniz:

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

veya daha az ayrıntılı:

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

2
Bu, en azından burada açıklanan bir hatadan ciddi bir şekilde etkilenir, burada bir değer her zaman orijinal konumundan değiştirilir. Bu ile giderilir . Ayrıca, FY içinde, genellikle yinelerler gelen Down to (veya sizi iterate eğer üzere , sen kabul cevap Nate gösterileri gibi indeksi almak). Fisher-Yates tartışmasının Modern Algoritma bölümüne bakın . let rnd = Int(arc4random_uniform(UInt32(idx + 1)))arr.count - 110arr.count - 1
Rob

1

İşler!!. organizmalar karışacak dizidir.

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

Swift 3.0'da bir diziyi tohumla karıştırmak işte böyle.

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

Ne kullanıyorum:

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

Basit Örnek:

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

Çalışma Dizisi Uzantısı (mutasyon ve mutasyon olmadan)

Swift 4.1 / Xcode 9

En iyi cevap reddedildi, bu yüzden Swift, Swift 4.1'in (Xcode 9) en yeni sürümünde bir diziyi karıştırmak için kendi uzantımı oluşturmayı kendime aldım:

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

Değişmeyen Karıştır çağırın [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)

Bu arrayrastgele bir sırayla yazdırılır .


Mutasyon Çağrısı Karıştır [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) 

Bu array, halihazırda rastgele karıştırılmış olan geçerli sırasına göre yazdırılır .


Herhangi bir sorunuz, öneriniz veya yorumunuz varsa, herkes için işe yaradığını umuyoruz!


0

SWIFT 4'te

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

Basit Swift For loop işlevini kullanmak istiyorsanız bunu kullanın ->

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 uzantısı kullanarak acı - -

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

0

Hızlı 4.2'den itibaren iki kullanışlı işlev vardır:

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

ve

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

-2

İşte oyun alanında çalışan bazı kodlar. Darwin'i gerçek bir Xcode projesine aktarmanız gerekmeyecek.

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
Bu, sonuçların düzgün olmayan bir dağılımını verir. Aynı zamanda bir Fisher-Yates karıştırmasının O (n) zamanında eşit dağıtılmış sonuçlar vereceği O (n log n) olacaktır.
pjs

Ayrıca drand48(), gibi bir tohum ayarlamadığınız sürece her zaman aynı sahte rasgele sayılar verirsrand48(Int(arc4random()))
Kametrixom 30:05

-3

XCode sürümünü 7.4 beta sürümüne yükselttiğimde "takas (& self [i], & self [j])" konumunda durur.
önemli hata: bir konumun kendisiyle değiştirilmesi desteklenmiyor

Ben i = j (takas fonksiyonu patlayacak) nedenini buldum

Bu yüzden aşağıdaki gibi bir koşul ekliyorum

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

YA! Benim için uygun.


Bu , orijinal sorunun cevabı değil , Chris'in cevabı hakkında bir yorum gibi görünüyor .
Mogsdad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.