count
返回一个IndexDistance
描述两个集合索引之间距离的类型。IndexDistance
必须是 a SignedInteger
,但不必是 anInt
并且可以不同于Index
. 因此无法创建范围0..<count - 1
。
一个解决方案是使用startIndex
andendIndex
而不是0
and count
:
extension MutableCollection where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffle() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
let j = Int(arc4random_uniform(UInt32(endIndex - i))) + i
if i != j {
swap(&self[i], &self[j])
}
}
}
}
另一个优点是这也适用于数组切片
(其中第一个元素的索引不一定为零)。
请注意,根据新的“Swift API 设计指南”,
shuffle()
是变异 shuffle 方法的“正确”名称,以及shuffled()
返回数组的非变异对应物:
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Iterator.Element] {
var list = Array(self)
list.shuffle()
return list
}
}
更新:一个(更通用的)Swift 3 版本已添加到
How do I shuffle an array in Swift? 同时。
对于Swift 4 (Xcode 9) ,必须通过调用集合的方法来替换对swap()
函数的调用。也不再需要swapAt()
对类型的限制:Index
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)
}
}
}
有关. _MutableCollection.swapAt(_:_:)
_swapAt
从Swift 4.2(Xcode 10,目前处于测试阶段)开始,实现了
SE-0202 Random Unification,
shuffle()
并且shuffled()
是 Swift 标准库的一部分。