如何在Swift中对数组进行洗牌?

 oDavid_仔o_880 发布于 2023-01-11 18:56

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

7 个回答
  • Swift 2.0中,GameplayKit可能会来救援!(iOS9或更高版本支持)

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

    2023-01-11 18:58 回答
  • 采用Nate的算法,我想看看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

    2023-01-11 18:58 回答
  • 在我的例子中,我遇到了在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
        }
    
    }
    

    2023-01-11 18:58 回答
  • 这是Nate为Swift 4 (Xcode 9)实现Fisher-Yates shuffle的一个版本.

    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 AddMutableCollection.swapAt(_:_:).

    Element是别名Iterator.Element.

    2023-01-11 18:59 回答
  • 编辑:正如其他答案所述,Swift 4.2 最终将随机数生成添加到标准库中,完成数组重排.

    但是,GameplayKit中的GKRandom/ GKRandomDistributionsuite仍然可以用于新RandomNumberGenerator协议 - 如果您向GameplayKit RNG添加扩展以符合新的标准库协议,您可以轻松获得:

    可发送的RNG(可在需要进行测试时重现"随机"序列)

    RNG牺牲了速度的稳健性

    产生非均匀分布的RNG

    ...并且仍然使用Swift中漂亮的新"本机"随机API.

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


    这里有一些很好的答案,以及一些很好的例子,说明如果你不小心,写你自己的shuffle可能容易出错.

    在iOS 9,macOS 10.11和tvOS 9(或更高版本)中,您不必编写自己的.在GameplayKit中有一个高效,正确的Fisher-Yates实现(尽管名称不仅仅适用于游戏).

    如果你只想要一个独特的shuffle:

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

    2023-01-11 18:59 回答
  • 这可能有点短:

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

    2023-01-11 18:59 回答
  • 这个答案详细介绍了如何在Swift 4.2+中使用快速统一的算法(Fisher-Yates),以及如何在各种先前版本的Swift中添加相同的功能.每个Swift版本的命名和行为都与该版本的变异和非变异排序方法相匹配.

    Swift 4.2+

    shuffle并且shuffled是原生的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]
    

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

    2023-01-11 19:00 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有