Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shuffle array swift 3

Tags:

swift

swift3

How can I convert the function below to to swift 3? Currently getting a Binary operator '..<' cannot be applied to operands of type 'Int' and 'Self.IndexDistance' error.

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

reference: https://stackoverflow.com/a/24029847/5222077

like image 960
kye Avatar asked Jun 15 '16 18:06

kye


People also ask

How do you shuffle an array?

Shuffle Array using Random Class We can iterate through the array elements in a for loop. Then, we use the Random class to generate a random index number. Then swap the current index element with the randomly generated index element. At the end of the for loop, we will have a randomly shuffled array.


2 Answers

count returns an IndexDistance which is the type describing the distance between two collection indices. IndexDistance is required to be a SignedInteger, but need not be an Int and can be different from Index. Therefore it is not possible to create the range 0..<count - 1.

A solution is to use startIndex and endIndex instead of 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])             }         }     } } 

Another advantage is that this also works correctly with array slices (where the index of the first element is not necessarily zero).

Note that according to the new "Swift API Design Guidelines", shuffle() is the "proper" name for a mutating shuffle method, and shuffled() for the non-mutating counterpart which returns an array:

extension Collection {     /// Return a copy of `self` with its elements shuffled     func shuffled() -> [Iterator.Element] {         var list = Array(self)         list.shuffle()         return list     } } 

Update: A (even more general) Swift 3 version has been added to How do I shuffle an array in Swift? in the meantime.


For Swift 4 (Xcode 9) one has to replace the call to the swap() function by a call to the swapAt() method of the collection. Also the restriction on the Index type is no longer needed:

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

See SE-0173 Add MutableCollection.swapAt(_:_:) for more information about swapAt.


As of Swift 4.2 (Xcode 10, currently in beta), with the implementation of SE-0202 Random Unification, shuffle() and shuffled() are part of the Swift standard library.

like image 191
Martin R Avatar answered Oct 01 '22 11:10

Martin R


There is a fisher-yates shuffle in Gamekit:

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

You can also pass in and store a random seed, so you get the same sequence of pseudorandom shuffle values every time you supply the same seed in case you need to recreate a 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) 
like image 22
Josh Homann Avatar answered Oct 01 '22 11:10

Josh Homann