Randomize two arrays the same way Swift
Using the shuffle()
method from How do I shuffle an array in Swift? and the ideas from How can I sort multiple arrays based on the sorted order of another array
you can shuffle the array indices and then re-order both (or more)
arrays accordingly:
let a = [1, 2, 3, 4]
let b = ["a", "b", "c", "d"]
var shuffled_indices = a.indices.shuffle()
let shuffled_a = Array(PermutationGenerator(elements: a, indices: shuffled_indices))
let shuffled_b = Array(PermutationGenerator(elements: b, indices: shuffled_indices))
print(shuffled_a) // [3, 1, 2, 4]
print(shuffled_b) // ["c", "a", "b", "d"]
Update for Swift 3 (Xcode 8): PermutationGenerator
does not
exist in Swift 3 anymore.
Using the shuffled()
method
from Shuffle array swift 3 the same can be achieved with
var shuffled_indices = a.indices.shuffled()
let shuffled_a = shuffled_indices.map { a[$0] }
let shuffled_b = shuffled_indices.map { b[$0] }
How do I shuffle an array in Swift?
This answer details how to shuffle with a fast and uniform algorithm (Fisher-Yates) in Swift 4.2+ and how to add the same feature in the various previous versions of Swift. The naming and behavior for each Swift version matches the mutating and nonmutating sorting methods for that version.
Swift 4.2+
shuffle
and shuffled
are native starting Swift 4.2. Example usage:
let x = [1, 2, 3].shuffled()
// x == [2, 3, 1]
let fiveStrings = stride(from: 0, through: 100, by: 5).map(String.init).shuffled()
// fiveStrings == ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffle()
// numbers == [3, 2, 1, 4]
Swift 4.0 and 4.1
These extensions add a shuffle()
method to any mutable collection (arrays and unsafe mutable buffers) and a shuffled()
method to any sequence:
extension MutableCollection {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 4.1
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
let i = index(firstUnshuffled, offsetBy: d)
swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Element] {
var result = Array(self)
result.shuffle()
return result
}
}
Same usage as in Swift 4.2 examples above.
Swift 3
These extensions add a shuffle()
method to any mutable collection and a shuffled()
method to any sequence:
extension MutableCollection where Indices.Iterator.Element == Index {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 3.2
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
self.swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Iterator.Element] {
var result = Array(self)
result.shuffle()
return result
}
}
Same usage as in Swift 4.2 examples above.
Swift 2
(obsolete language: you can't use Swift 2.x to publish on iTunes Connect starting July 2018)
extension MutableCollectionType 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 startIndex ..< endIndex - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension CollectionType {
/// Return a copy of `self` with its elements shuffled.
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
Usage:
[1, 2, 3].shuffle()
// [2, 3, 1]
let fiveStrings = 0.stride(through: 100, by: 5).map(String.init).shuffle()
// ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffleInPlace()
// [3, 2, 1, 4]
Swift 1.2
(obsolete language: you can't use Swift 1.x to publish on iTunes Connect starting July 2018)
shuffle
as a mutating array method
This extension will let you shuffle a mutable Array
instance in place:
extension Array {
mutating func shuffle() {
if count < 2 { return }
for i in 0..<(count - 1) {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
swap(&self[i], &self[j])
}
}
}
var numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.shuffle() // e.g., numbers == [6, 1, 8, 3, 2, 4, 7, 5]
shuffled
as a non-mutating array method
This extension will let you retrieve a shuffled copy of an Array
instance:
extension Array {
func shuffled() -> [T] {
if count < 2 { return self }
var list = self
for i in 0..<(list.count - 1) {
let j = Int(arc4random_uniform(UInt32(list.count - i))) + i
swap(&list[i], &list[j])
}
return list
}
}
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let mixedup = numbers.shuffled() // e.g., mixedup == [6, 1, 8, 3, 2, 4, 7, 5]
Shuffle array swift 3
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.
How to avoid generating the same random String twice in a row in Swift?
Since you only care about not repeating the value as the next value, just remember the previous value and reject the next value if it is the same as the previous value.
Here's a playground example. First, we try this the simplest way:
let pep = ["manny", "moe", "jack"]
func fetchRandomPep() -> String {
return pep.randomElement()!
}
for _ in 1...100 {
let result = fetchRandomPep()
print(result)
}
Well, you probably got many repeated results. Let's prevent that by writing our loop in a different way:
var prev = ""
for _ in 1...100 {
var result = fetchRandomPep()
while result == prev {
result = fetchRandomPep()
}
prev = result
print(result)
}
Now there are no repetitions!
Shuffle/Randomize Questions from an Array with no Repetition (SWIFT)
You seem to be shuffling the list
every time you call updateQuestion
which seems to be the issue here. You are only supposed to call the shuffle
once and iterate through the questions one by one. To fix the issue remove the shuffle from updateQuestion
and add it in viewDidLoad
or just call it once in updateQuestion
based on a condition like this:
if questionNumber == 1 {
allQuestions.list.shuffle()
}
Related Topics
How to Find a Maximum Value in a Swift Dictionary
How to Convert Unix Timestamp into Swift Nsdate Object
Swift How to Format a Large Number with Thousands Separators
(Cross-)Compiling Swift for Raspberry Pi
Xcode Source Kit Will Not Stop Crashing with Swift
Swift "Retry" Logic on Request
Structuring Data for Chat App in Firebase
Date/Time Natural Language Approximation in Swift
Getting Data Out of Completionhandler in Swift in Nsurlconnection
Swift Optional Variable Assignment with Default Value (Double Question Marks)
Error: Couldn't Irgen Expression, No Additional Error
Uitextview Linktextattributes Font Attribute Not Applied to Nsattributedstring
What Does Cloning a Github Repository Mean
Apple Vision Framework - Text Extraction from Image
How to Correctly Initialize an Unsafepointer in Swift
Swiftui: Stop an Animation That Repeats Forever
Swift Package Manager Dynamic Library
Using Reflection to Set Object Properties Without Using Setvalue Forkey