arrays - 如何在 Swift 中打乱数组?

标签 arrays swift shuffle

.shuffle() 和 .shuffled() 是 Swift 的一部分

<小时/>

原始历史问题:

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

最佳答案

这个答案详细介绍了如何在 Swift 4.2+ 中使用快速且统一的算法 (Fisher-Yates) 进行洗牌,以及如何在 Swift 的各个早期版本中添加相同的功能。每个 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 示例中的用法相同。

<小时/>

swift 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 示例中的用法相同。

<小时/>

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

关于arrays - 如何在 Swift 中打乱数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38417585/

相关文章:

javascript - 在javascript中将列表中的单词与句子中的单词相匹配的最佳方法是什么?

ios - AVPlayerViewController 是否自动带有 AVPlayer 对象?

java - stdrandom shuffle 方法的工作原理

php - 在 OptionsResolver 中使用多维数组

javascript - 如何在不停止遍历的情况下删除 forEach 循环中的项目

javascript - 从javascript函数返回数组到objective-c xcode

arrays - 在 Swift 4 中从 Url 获取 JSON 数据

ios - 使用 BSImagePicker Swift4 在图库中显示刚刚选定的图像

使用 glob 的 php echo 文件夹名称

c++ - 完美的shuffle和unshuffle,没有辅助数组