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

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

【问题讨论】:

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

标签: arrays swift shuffle


【解决方案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 4Nate'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()。 – 请参阅stackoverflow.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 shuffleimmutable 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 的评论,而不是对原始问题的回答。
                                    猜你喜欢
                                    • 2012-11-25
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2023-03-03
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2015-10-28
                                    相关资源
                                    最近更新 更多