/ / Tableau de mélange swift 3 - swift, swift3

Mélanger le tableau swift 3 - swift, swift3

Comment puis-je convertir la fonction ci-dessous en swift 3? En train d'obtenir 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

Réponses:

77 pour la réponse № 1

count renvoie un IndexDistance qui est le type décrivant la distance entre deux indices de collection. IndexDistance est doit être un SignedInteger, mais ne doit pas être un Int et peut être différent de Index. Par conséquent, il n'est pas possible de créer la gamme 0..<count - 1.

Une solution est d'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 array des tranches (où l'indice du premier élément n'est pas nécessairement zéro).

Notez que selon le nouveau "Directives de conception des API rapides", shuffle() est le "bon" nom pour une méthode de mutation aléatoire, et shuffled() pour la contrepartie non mutante 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
}
}

Mettre à jour: Une version (encore plus générale) de Swift 3 a été ajoutée à Comment puis-je mélanger un tableau dans Swift? pendant ce temps.


Pour Swift 4 (Xcode 9) on doit remplacer l'appel à la swap() fonctionner par un appel au swapAt() méthode de la collection. Aussi la restriction sur la Index le type 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.


À partir de Swift 4.2 (Xcode 10, actuellement en version bêta), avec la mise en œuvre de SE-0202 Unification Aléatoire, shuffle() et shuffled() font partie de la bibliothèque standard Swift.


9 pour la réponse № 2

Il y a un mélange de pêcheurs et de pêcheurs dans Gamekit:

import GameKit
let unshuffledArray = [1,2,3,4]
let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray)
print(shuffledArray)

Vous pouvez également passer et stocker une graine aléatoire, de sorte que vous obteniez la même séquence de valeurs de mélange pseudo-aléatoires à 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)

7 pour la réponse № 3

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])
}
}
}

0 pour la réponse № 4

Vous pouvez utiliser le framework NSArray Extension de 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]