.shuffle()和.shuffled()是Swift的一部分
原历史问题:
我如何随机或洗牌在Swift数组中的元素?例如,如果我的数组包含52张扑克牌,我想要洗牌数组以洗牌牌组。
.shuffle()和.shuffled()是Swift的一部分
原历史问题:
我如何随机或洗牌在Swift数组中的元素?例如,如果我的数组包含52张扑克牌,我想要洗牌数组以洗牌牌组。
当前回答
这是我所使用的:
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]
其他回答
这是如何在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])
}
}
}
以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作为索引
在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"]
这个答案详细介绍了如何在Swift 4.2+中使用快速和统一的算法(Fisher-Yates)进行洗牌,以及如何在之前的各种Swift版本中添加相同的功能。每个Swift版本的命名和行为都与该版本的突变和非突变排序方法相匹配。
Swift 4 + 2。
shuffle和shuffle是原生开始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
(过时的语言:你不能使用Swift 2。x将于2018年7月在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
(过时的语言:你不能使用Swift 1。x将于2018年7月在iTunes Connect上发布)
Shuffle是一种可变数组方法
这个扩展将让你洗牌可变数组实例的地方:
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]
shuffle是一种非突变数组方法
这个扩展可以让你检索一个数组实例的打乱副本:
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]
你也可以使用通用交换函数,实现前面提到的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)))])
}