随机排列数组 swift 3
Shuffle array swift 3
如何将下面的函数转换为 swift 3
?当前出现 Binary operator '..<' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'
错误。
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 }
for i in 0..<count - 1 { //error takes place here
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
参考:
我建议简单地改组数组而不是尝试将其扩展到一般集合:
extension Array {
mutating func shuffle () {
for i in (0..<self.count).reversed() {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(self[ix1], self[ix2]) = (self[ix2], self[ix1])
}
}
}
count
returns 一个 IndexDistance
这是描述的类型
两个集合索引之间的距离。 IndexDistance
是
必须是 SignedInteger
,但不必是 Int
,并且可以
不同于 Index
。因此无法创建
范围 0..<count - 1
.
一个解决方案是使用 startIndex
和 endIndex
而不是 0
和 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])
}
}
}
}
另一个优点是这也适用于数组 slices
(第一个元素的索引不一定为零)。
请注意,根据新的 "Swift API Design Guidelines",
shuffle()
是变异洗牌方法的 "proper" 名称,
和 shuffled()
对于 returns 一个数组的非变异对应物:
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Iterator.Element] {
var list = Array(self)
list.shuffle()
return list
}
}
更新:A(更通用)Swift3版本已添加
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)
}
}
}
有关 swapAt
的更多信息,请参阅 SE-0173 Add MutableCollection.swapAt(_:_:)
。
自 Swift 4.2(Xcode 10,目前处于测试阶段),随着
SE-0202 Random Unification,
shuffle()
和 shuffled()
是 Swift 标准库的一部分。
Gamekit 中有一个 fisher-yates shuffle:
import GameKit
let unshuffledArray = [1,2,3,4]
let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray)
print(shuffledArray)
您还可以传入并存储一个随机种子,这样每次您提供相同的种子时都会得到相同的伪随机随机值序列,以防您需要重新创建模拟。
import GameKit
let unshuffledArray = [1,2,3,4]
let randomSource = GKLinearCongruentialRandomSource(seed: 1)
let shuffledArray = randomSource.arrayByShufflingObjects(in: unshuffledArray)
//Always [1,4,2,3]
print(shuffledArray)
为此,您可以使用 GameplayKit 框架中的 NSArray 扩展:
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
?当前出现 Binary operator '..<' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'
错误。
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 }
for i in 0..<count - 1 { //error takes place here
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
参考:
我建议简单地改组数组而不是尝试将其扩展到一般集合:
extension Array {
mutating func shuffle () {
for i in (0..<self.count).reversed() {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(self[ix1], self[ix2]) = (self[ix2], self[ix1])
}
}
}
count
returns 一个 IndexDistance
这是描述的类型
两个集合索引之间的距离。 IndexDistance
是
必须是 SignedInteger
,但不必是 Int
,并且可以
不同于 Index
。因此无法创建
范围 0..<count - 1
.
一个解决方案是使用 startIndex
和 endIndex
而不是 0
和 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])
}
}
}
}
另一个优点是这也适用于数组 slices (第一个元素的索引不一定为零)。
请注意,根据新的 "Swift API Design Guidelines",
shuffle()
是变异洗牌方法的 "proper" 名称,
和 shuffled()
对于 returns 一个数组的非变异对应物:
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Iterator.Element] {
var list = Array(self)
list.shuffle()
return list
}
}
更新:A(更通用)Swift3版本已添加 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)
}
}
}
有关 swapAt
的更多信息,请参阅 SE-0173 Add MutableCollection.swapAt(_:_:)
。
自 Swift 4.2(Xcode 10,目前处于测试阶段),随着
SE-0202 Random Unification,
shuffle()
和 shuffled()
是 Swift 标准库的一部分。
Gamekit 中有一个 fisher-yates shuffle:
import GameKit
let unshuffledArray = [1,2,3,4]
let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray)
print(shuffledArray)
您还可以传入并存储一个随机种子,这样每次您提供相同的种子时都会得到相同的伪随机随机值序列,以防您需要重新创建模拟。
import GameKit
let unshuffledArray = [1,2,3,4]
let randomSource = GKLinearCongruentialRandomSource(seed: 1)
let shuffledArray = randomSource.arrayByShufflingObjects(in: unshuffledArray)
//Always [1,4,2,3]
print(shuffledArray)
为此,您可以使用 GameplayKit 框架中的 NSArray 扩展:
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]