如何在 Swift 中打乱数组?

Posted

技术标签:

【中文标题】如何在 Swift 中打乱数组?【英文标题】:How do I shuffle an array in Swift? 【发布时间】:2014-07-24 11:00:09 【问题描述】:

如何在 Swift 中随机化或打乱数组中的元素?例如,如果我的阵列由 52 张扑克牌组成,我想洗牌阵列以便洗牌。

【问题讨论】:

这不是特定于任何语言的。只需应用任何洗牌算法... @Mithrandir 这不是真的。在 Ruby 中,可以选择 array.shuffle。无需实现您自己的版本。我猜 OP 正在寻找类似的东西。 【参考方案1】:

此答案详细说明了如何在 Swift 4.2+ 中使用快速且统一的算法(Fisher-Yates)进行洗牌,以及如何在 Swift 的各个早期版本中添加相同的功能。每个 Swift 版本的命名和行为与该版本的变异和非变异排序方法相匹配。

斯威夫特 4.2+

shuffleshuffled 从 Swift 4.2 开始是原生的。示例用法:

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

这些扩展将shuffle() 方法添加到任何可变集合(数组和不安全的可变缓冲区),并将shuffled() 方法添加到任何序列:

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
    

与上述 Swift 4.2 示例中的用法相同。


斯威夫特 3

这些扩展将shuffle() 方法添加到任何可变集合,并将shuffled() 方法添加到任何序列:

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
    

与上述 Swift 4.2 示例中的用法相同。


斯威夫特 2

(过时的语言:从 2018 年 7 月开始,您不能使用 Swift 2.x 在 iTunes Connect 上发布)

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
    

用法:

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

斯威夫特 1.2

(过时的语言:从 2018 年 7 月开始,您不能使用 Swift 1.x 在 iTunes Connect 上发布)

shuffle 作为变异数组方法

这个扩展可以让你随机播放一个可变的Array 实例:

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 作为非变异数组方法

此扩展程序可让您检索 Array 实例的随机副本:

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]

【讨论】:

如果你想要 Swift 1.2 中的函数版本,它需要一些更新,因为 countElements 已经消失,它的替换,count,现在返回一个 T.Index.Distance 所以约束需要在C.Index.Distance == Int上。这个版本应该可以工作:gist.github.com/airspeedswift/03d07a9dc86fabdc370f 这些是实际输出——Fisher-Yates 应该返回源的无偏随机排列,因此不要求特定元素应该移动。 保证没有元素移动超过一次,但有时“移动”是相同的索引。最简单的情况是考虑[1, 2].shuffled()——是否应该每次都返回[2, 1] 我在 mutating array 函数的顶部添加了if count &gt; 0,以防止在传递空数组时收到“致命错误:Can't form Range with end @Jan:是的,在交换之前添加guard i != j else continue 。我提交了雷达,但新行为是故意的。 实际上shuffleInPlace 可能会在集合索引不从零开始时崩溃,例如对于数组切片。 for i in 0..&lt;count - 1 应该是 for i in startIndex ..&lt; endIndex - 1(然后转换到 Swift 3 变得几乎是微不足道的)。【参考方案2】:

编辑:如其他答案所述,Swift 4.2 finally 将随机数生成添加到标准库中,并完成了数组改组。

但是,GameplayKit 中的 GKRandom / GKRandomDistribution 套件仍然可以与新的 RandomNumberGenerator 协议一起使用 — 如果您向 GameplayKit RNG 添加扩展以符合新的标准库协议,您可以轻松获得:

可发送的 RNG(可以在需要测试时重现“随机”序列) 为了速度而牺牲稳健性的 RNG 产生非均匀分布的 RNG

...并且仍然使用 Swift 中不错的新“原生”随机 API。

此答案的其余部分涉及此类 RNG 和/或它们在较旧的 Swift 编译器中的使用。


这里已经有一些很好的答案,以及一些很好的说明,说明为什么如果你不小心编写自己的 shuffle 会容易出错。

ios 9、macOS 10.11 和 tvOS 9(或更高版本)中,您不必自己编写。 GameplayKit 中有an efficient, correct implementation of Fisher-Yates(尽管名称如此,但它不仅仅用于游戏)。

如果您只想要一个独特的随机播放:

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

如果您希望能够复制 shuffle 或一系列 shuffle,请选择并播种特定的随机源;例如

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

在 iOS 10 / macOS 10.12 / tvOS 10 中,还有一个方便的语法用于通过 NSArray 上的扩展名进行改组。当然,当您使用 Swift Array 时,这有点麻烦(并且在返回 Swift 时它会丢失其元素类型):

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

但是为它制作一个类型保留的 Swift 包装器非常容易:

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

【讨论】:

让我想知道 GameplayKit 中还有哪些我从未探索过的有用实用程序! 图形搜索、树搜索、规则系统...lots of stuff这对游戏设计和其他方面都有帮助。 在 Swift 3/iOS 10 中,这已更改为:let shuffled = lcg.arrayByShufflingObjects(in: array)【参考方案3】:

Swift 2.0 中,GameplayKit 可能会派上用场! (iOS9 或更高版本支持)

import GameplayKit

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

【讨论】:

导入 GameplayKit 只是为了获得洗牌数组听起来不是个好主意 为什么?它是系统的一部分,不会添加到二进制文件中。 您还可以将导入范围简单地设置为import GameplayKit.GKRandomSource【参考方案4】:

这里可能有点短:

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

【讨论】:

@moby sort 函数需要一个闭包来对元素进行排序。这个闭包有两个参数(elem1,elem2),如果第一个值应该出现在第二个值之前,则必须返回 true,否则返回 false。如果我们返回一个随机布尔值......那么我们只是把整个事情搞混了:) 有没有数学家来证实或证伪? 正如 pjs 在回应另一个非常相似的答案时指出的那样,这将不会生成均匀分布的结果。使用Fisher-Yates Shuffle,如 Nate Cook 的回答所示。 这是一个聪明的技巧,但在随机播放的质量方面却很糟糕。一方面,这个闭包应该使用arc4random_uniform(),因为它目前受到模偏差的影响。其次,输出很大程度上依赖于排序算法(不看源码我们不知道)。 继续使用这种更简单的方法,这似乎工作得很好:collection.sorted _,_ in arc4random_uniform(1) == 0 【参考方案5】:

采用Nate's 算法,我想看看它在 Swift 2 和协议扩展中的效果。

这是我想出来的。

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
    

现在,任何MutableCollectionType 都可以使用这些方法,因为它使用Int 作为Index

【讨论】:

【参考方案6】:

在我的例子中,我在交换 Array 中的对象时遇到了一些问题。然后我挠了挠头,开始重新发明***。

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


【讨论】:

【参考方案7】:

这是 Swift 4 的 Nate's implementation of the Fisher-Yates shuffle 版本 (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
    

变化是:

约束Indices.Iterator.Element == Index 现在是一部分 的Collection 协议,不需要强加于 不再扩展。 交换元素必须通过在集合上调用swapAt() 来完成, 比较SE-0173 Add MutableCollection.swapAt(_:_:)ElementIterator.Element 的别名。

【讨论】:

【参考方案8】:

斯威夫特 4 在 for 循环中打乱数组的元素,其中 i 是混合比

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

或带有扩展名 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
        
    

【讨论】:

【参考方案9】:

这是我用的:

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

【讨论】:

【参考方案10】:

从 swift 4.2 开始,有两个方便的功能:

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

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

【讨论】:

【参考方案11】:

Swift 3 解决方案,遵循@Nate Cook 的回答:(如果索引以 0 开头,则工作,请参阅下面的 cmets)

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

【讨论】:

如果集合索引确实从 0 开始,这可能会崩溃,例如对于数组切片。尝试多次运行var a = [1, 2, 3, 4, 5, 6][3..&lt;6]; a.shuffleInPlace()。 – 请参阅***.com/a/37843901/1187415 以获得正确的解决方案。【参考方案12】:

这是以最简单的方式完成的。import Gamplaykit 给您的 VC 并使用以下代码。在 Xcode 8 中测试。

 import GameplayKit

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

 override func viewDidLoad() 
    super.viewDidLoad()

    print(array.shuffled())  

如果你想从一个数组中得到一个洗牌的字符串,你可以使用下面的代码..

func suffleString() 

    let ShuffleArray = array.shuffled()

    suffleString.text = ShuffleArray.first as? String

    print(suffleString.text!)


【讨论】:

【参考方案13】:

在 Swift 3 中,如果您想在适当的位置打乱数组或从数组中获取新的打乱数组,AnyIterator 可以为您提供帮助。这个想法是从你的数组中创建一个索引数组,用AnyIterator 实例和swap(_:_:) 函数对这些索引进行洗牌,并将这个AnyIterator 实例的每个元素映射到数组的对应元素。


以下 Playground 代码展示了它的工作原理:

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

您可以重构之前的代码并在 Array 扩展中创建一个 shuffled() 函数,以便从数组中获取新的打乱数组:

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] 
    


用法:

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

作为前面代码的替代方案,您可以在 Array 扩展内创建一个 shuffle() 函数,以便在适当的位置打乱数组:

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] 
    


用法:

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

【讨论】:

【参考方案14】:

如果你想使用简单的 Swift For 循环函数,请使用这个 ->

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

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

【讨论】:

【参考方案15】:

您也可以使用通用swap 函数并实现提到的Fisher-Yates:

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

或者不那么冗长:

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

【讨论】:

这至少会遇到一个严重的off by one错误described here,其中一个值总是从其原始位置交换.这可以通过let rnd = Int(arc4random_uniform(UInt32(idx + 1))) 解决。此外,在 FY 中,您通常从 arr.count - 1 迭代到 1 (或者如果您从 0 迭代到 arr.count - 1,您会选择 Nate 在接受的答案中显示的索引)。请参阅 Fisher-Yates 讨论的 Modern Algorithm section。【参考方案16】:

有效!!。生物体是要洗牌的数组。

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

【讨论】:

【参考方案17】:

工作数组扩展(变异和非变异)

斯威夫特 4.1 / Xcode 9

最佳答案已被弃用,因此我自己创建了自己的扩展,以在最新版本的 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
    


调用非变异随机播放[Array] -&gt; [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)

这会以随机顺序打印array


调用变异洗牌[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) 

这会按当前顺序打印array,该顺序已经随机打乱。


希望这对大家有用,如果您有任何问题、建议或 cmets,请随时提问!

【讨论】:

【参考方案18】:

在 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

【讨论】:

【参考方案19】:

Swift 4.2 中,现在有一个用于 mutable shuffle 和 immutable shuffled 的方法。你可以阅读更多关于随机生成和数组的内容here。

【讨论】:

【参考方案20】:

这是在 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])
        
    

【讨论】:

【参考方案21】:
let shuffl = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: arrayObject)

【讨论】:

【参考方案22】:

这是我用的:

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]

【讨论】:

【参考方案23】:

简单示例:

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]

【讨论】:

【参考方案24】:

这里有一些在 Playground 中运行的代码。您不需要在实际的 Xcode 项目中导入 Darwin。

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)

【讨论】:

这给出了结果的非均匀分布。它也将是 O(n log n),其中 Fisher-Yates shuffle 将在 O(n) 时间内给出均匀分布的结果。 另外,drand48() 每次都会给出相同的伪随机数,除非您使用 srand48(Int(arc4random())) 设置种子【参考方案25】:

当我将 xCode 版本升级到 7.4 beta 时,它停在“swap(&self[i], &self[j])”。 致命错误:不支持与自身交换位置

我找到了i = j的原因(swap函数会爆炸)

所以我添加如下条件

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

耶!对我来说没问题。

【讨论】:

这似乎是对Chris's answer 的评论,而不是对原始问题的回答。

以上是关于如何在 Swift 中打乱数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何在给定范围内创建一个随机打乱数字的 int 数组 [重复]

如何在保持两个字段原始顺序的情况下打乱行?

如何打乱问题并显示数组的一项

如何在 Swift 中的位置上设置加扰字母的动画?

如何在不重复单词并遍历整个数组的情况下从数组中随机播放文本? (迅速)

matlab中如何将某一数组中数据进行打乱,有没有相应的函数,谢谢,在线等。