快速sorting3
如何将下面的函数转换为swift 3
? 目前得到一个Binary operator '..<' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'
错误的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]) } } }
参考: https : //stackoverflow.com/a/24029847/5222077
count
返回一个IndexDistance
,它是描述两个集合索引之间距离的types。 IndexDistance
需要是一个SignedInteger
,但不一定是一个Int
,可以不同于Index
。 因此无法创build范围0..<count - 1
。
一个解决scheme是使用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]) } } } }
另一个优点是这也适用于数组切片 (其中第一个元素的索引不一定是零)。
请注意,根据新的“Swift APIdevise指南” , shuffle()
是突变的shuffle方法的“正确”名称, shuffle()
是返回数组的非突变副本。
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版本已被添加到如何在Swift中洗牌数组? 同时。
对于Swift 4(Xcode 9),必须通过调用集合的swapAt()
方法来调用swap()
函数。 此外, Index
types的限制不再需要:
extension MutableCollection { /// 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 indices.dropLast() { let diff = distance(from: i, to: endIndex) let j = index(i, offsetBy: numericCast(arc4random_uniform(numericCast(diff)))) swapAt(i, j) } } }
有关MutableCollection.swapAt(_:_:)
的更多信息,请参阅SE-0173添加MutableCollection.swapAt(_:_:)
。
Gamekit中有一个fisher-yates shuffle:
import GameKit let unshuffledArray = [1,2,3,4] let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray) print(shuffledArray)
您还可以传入并存储一个随机种子,这样每次提供相同的种子时,就可以得到相同的伪随机序列值,以防需要重新创build模拟。
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)
我会build议简单地洗牌数组,而不是试图扩展到一般的集合:
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]) } } }
你可以使用GameplayKit框架的NSArray Extension来实现这个function:
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]