Comment puis-je convertir la fonction ci-dessous en Swift 3
? Vous obtenez actuellement un Binary operator '..<' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'
Erreur.
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])
}
}
}
référence: https://stackoverflow.com/a/24029847/5222077
count
renvoie un IndexDistance
qui est le type décrivant la distance entre deux indices de collection. IndexDistance
doit être un SignedInteger
, mais pas nécessairement un Int
et peut être différent de Index
. Il n'est donc pas possible de créer la plage 0..<count - 1
.
Une solution consiste à utiliser startIndex
et endIndex
au lieu de 0
Et 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])
}
}
}
}
Un autre avantage est que cela fonctionne également correctement avec le tableau slices (où l'indice du premier élément n'est pas nécessairement nul).
Notez que selon le nouveau "Swift API Design Guidelines" , shuffle()
est le "bon" nom pour une méthode de shuffle mutant, et shuffled()
pour le non - homologue mutant qui retourne un tableau:
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Iterator.Element] {
var list = Array(self)
list.shuffle()
return list
}
}
Mise à jour: A (encore plus général) Swift 3 a été ajoutée à Comment mélanger un tableau dans Swift? in pendant ce temps.
Pour Swift 4 (Xcode 9) , il faut remplacer l'appel à la fonction swap()
par un appel à la fonction swapAt()
méthode de la collection. De plus, la restriction sur le type Index
n'est plus nécessaire:
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)
}
}
}
Voir SE-0173 Ajouter MutableCollection.swapAt(_:_:)
pour plus d'informations sur swapAt
.
Depuis Swift 4.2 (Xcode 10, actuellement en version bêta), avec l'implémentation de SE-0202 Random Unification , shuffle()
et shuffled()
font partie de la bibliothèque standard Swift.
Il y a un remaniement des pêcheurs-yates dans Gamekit:
import GameKit
let unshuffledArray = [1,2,3,4]
let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray)
print(shuffledArray)
Vous pouvez également transmettre et stocker une graine aléatoire, de sorte que vous obtenez la même séquence de valeurs de mélange pseudo-aléatoire chaque fois que vous fournissez la même graine au cas où vous auriez besoin de recréer une simulation.
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)
Je suggérerais simplement de mélanger les tableaux au lieu d'essayer d'étendre cela aux collections en général:
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])
}
}
}
Vous pouvez utiliser l'extension NSArray du framework GameplayKit pour cela:
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]