Parallel array elements assignment causes crash in Swift - arrays

I want set elements of array concurrently,so I write code to test:
let Count = 1000
let SubRangeCount = 100
var ary = [Int](repeating: 0, count: Count)
let times = Count/SubRangeCount
let _ = DispatchQueue.global(qos: .userInitiated)
DispatchQueue.concurrentPerform(iterations: times){ idx in
for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
ary[i] = Int.random(in: 0...Int.max)
}
}
}
above code working great!
But when I change like this:
let Count = 10000
let SubRangeCount = 1000
It's crash!
In playground it complain "Fatal error: UnsafeMutablePointer.initialize overlapping range: file Swift/UnsafePointer.swift, line 832"
But you can see every range of array's assignments is NOT overlapping!
So how to fix it? Thanks!

Array is not thread safe on Swift so you need to synchronise access to it, for instance with objc_sync_enter and objc_sync_exit:
func synchronized<T : AnyObject, U>(_ obj: T, closure: () -> U) -> U {
objc_sync_enter(obj)
defer {
objc_sync_exit(obj)
}
return closure()
}
var arr = [Int](repeating: 0, count: 100_000)
let obj = arr as NSObject // Object to synchronise
DispatchQueue.concurrentPerform(iterations: 100_000){ index in
synchronized(obj) {
arr[index] = Int.random(in: 0...Int.max)
}
}

Here the array is concurrently mutated from multiple threads, which creates a race condition. To avoid this you have to perform the critical operation in a thread-safe way. You can take help from Grand Central Dispatch in the Apple platform - which lets us deal with threads using its much simpler queue-based abstractions.
let Count = 10000
let SubRangeCount = 1000
var ary = [Int](repeating: 0, count: Count)
let times = Count/SubRangeCount
let serialQueue = DispatchQueue(label: "serial.Queue")
DispatchQueue.concurrentPerform(iterations: times){ idx in
print(idx)
for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
serialQueue.async {
ary[i] = Int.random(in: 0...Int.max)
}
}
}
You can also use lock.
let Count = 10000
let SubRangeCount = 1000
var ary = [Int](repeating: 0, count: Count)
let lock = NSLock()
let times = Count/SubRangeCount
DispatchQueue.concurrentPerform(iterations: times){ idx in
print(idx)
for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
lock.lock()
ary[i] = Int.random(in: 0...Int.max)
lock.unlock()
}
}

I found a workaround for it:
DispatchQueue.concurrentPerform(iterations: enumTimes){ idx in
var subAry = ary1[(idx * SubRangeCount)..<((idx+1) * SubRangeCount)]
for i in subAry.indices {
subAry[i] = Int.random(in: 0...Int.max)
}
}
It's no Crash, and fast 3x-10x than serialize assignments.

Related

Increment value in an array of dictionaries

I'm trying to calculate the number of times a specific number is rolled in a set of six six-sided dice, to determine wether or not I have three of a kind, four of a kind, etc.
I can pull the face value of each die rolled and compare it to the faces on a 6 sided die but can't get the "qtyRolled" key/value to increment.
func rollDice() {
currentRoll.removeAll()
for _ in currentDiceArray {
let num: UInt32 = arc4random_uniform(UInt32(currentDieFaceArray.count))
let currentDieData = currentDieFaceArray[Int(num)]
let faceValue = currentDieData["faceValue"]
currentRoll.append(faceValue as! Int)
}
print(currentRoll)
getQtyOfDieFaces()
//checkForScoringCombos()
}
func getQtyOfDieFaces() {
for die in currentRoll {
for dieData in currentDieFaceArray {
var currentDieData = dieData
let qtyRolled = currentDieData["qtyRolled"] as! Int
let faceValue = currentDieData["faceValue"] as! Int
print("faceValue: \(faceValue)")
print("Die: \(die)")
if faceValue == die {
currentDieData["qtyRolled"] = qtyRolled + 1 as AnyObject
}
}
}
for currentDieData in currentDieFaceArray {
print(currentDieData["qtyRolled"]!)
}
}
Here are my data structures
var currentDieFaceArray = [[String:AnyObject]]()
var currentDiceArray:[[String:AnyObject]] = [[:]]
var currentRoll: [Int] = []
I'd recommend ditching the dictionaries unless you really need them, as you're really just dealing with properties of a struct/class. I'm going to assume you're using the currentDieFaceArray method so that you can make this generic for non-linear dice faces of other dimensions (e.g. you can have a four-sided dice with the face values [1, 4, 6, 8]). If this isn't the case, you can simplify further I'm sure with a simple array of counts. But here's an example with your method (probably has other possible optimisations).
class DieFaceDefn
{
let faceValue : Int
var countThisRoll : Int = 0
init(faceValue: Int)
{
self.faceValue = faceValue
}
}
var diceFaces: [DieFaceDefn] = []
let numberOfCurrentDice = 5
func setupDice()
{
diceFaces.append(DieFaceDefn(faceValue: 1))
diceFaces.append(DieFaceDefn(faceValue: 2))
...
}
var currentRoll: [Int] = []
func rollDice()
{
currentRoll.removeAll()
diceFaces.forEach { $0.countThisRoll = 0 }
for _ in 0..<numberOfCurrentDice
{
let num: UInt32 = arc4random_uniform(UInt32(diceFaces.count))
let currentDieData = diceFaces[Int(num)]
let faceValue = currentDieData.faceValue
currentRoll.append(faceValue)
currentDieData.countThisRoll += 1
}
print(currentRoll)
diceFaces.forEach { print("\($0.faceValue): \($0.countThisRoll)") }
}

Does Swift offer any built-in function to return the result of appending to an immutable array?

Writing the question and answer from here, I'm curious to know if there is any simpler way to write the following:
var nums = [1,2,3]
let sum1 = nums.reduce([Int]()){
let temp = $0
temp.append($1)
return temp
}
I know I can do:
var nums = [1,2,3]
let sum1 = nums.reduce([Int]()){
return $0 + [$1]
}
But that comes off as a hack.
To explain this better, I want to get closer to the example (from docs) below, just that it should be for an array:
let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
x + y
})
EDIT:
Since folks asked what was I trying to achieve:
I was doing the leetcode's group Anagram's challenge.
My solution was:
struct WordTraits: Equatable{
let count: Int
let charactersSet: Set<Character>
}
struct Word: Equatable{
let string: String
let wordTraits: WordTraits
}
class Solution{
func groupAnagrams(_ strs: [String]) -> [[String]]{
var words : [Word] = []
var answers : [(traits: WordTraits, words: [Word])] = []
var count = 0
strs.forEach{ str in
count += 1
let count = str.count
let string = str
let characterSet = Set(str)
let wordTraits = WordTraits(count: count, charactersSet: characterSet)
let word = Word(string: string, wordTraits: wordTraits)
words.append(word)
}
while words.count != 0{
let word = words[0]
let traits = word.wordTraits
var isWordAdded = false
for (i, answer) in answers.enumerated(){
if answer.traits == traits{
answers[i].words.append(word)
isWordAdded = true
break
}
}
if !isWordAdded{
answers.append((traits: traits, words:[word]))
}
words.removeFirst()
}
let emptyArray : [[String]] = []
let finalAnswer = answers.reduce(emptyArray, { total, answer in
let strings : [String] = answer.words.reduce([String](), {
return $0 + [$1.string]
})
return total + [strings]
})
return finalAnswer
}
}
let s = Solution()
print(s.groupAnagrams(["ate", "eta", "beta", "abet"])) // [["ate", "eta"], ["beta", "abet"]]
reduce(..) has to know which type it is working with. To infer this it can use the return type or the type of the first argument. So you can also write:
var nums = [1,2,3]
let sum1: [Int] = nums.reduce([]){
return $0 + [$1]
}
[$1] can't be replaced with $1 because +-operator between value and collection is undefined.
Nope. But you can add it:
extension Array {
func appending(_ newElement: Element) -> Array<Element> {
return self + [newElement]
}
func appending(contentsOf sequence: Sequence) -> Array<Element> {
return self + sequence
}
}
Um, how about the + operator?
let nums = [1, 3, 5]
let more = nums + [7]
Your code is trying to convert a complex structure to an array of arrays. You can use map for this.
This should work:
let finalAnswer = answers.map { answer in
answer.words.map {
$0.string
}
}
Edit:
I was able to solve it using minimal code:
class Solution {
func groupAnagrams(_ words: [String]) -> [[String]] {
let processedWords = words.map {
(key: String($0.sorted()), value: $0)
}
return Dictionary(grouping: processedWords, by: { $0.key }).map { groupedValue in
groupedValue.value.map {
$0.value
}
}
}
}
You've greatly overcomplicated your computation of "final answers". It could just be:
return answers.map { $0.words.map { $0.string } }

Count Items in an Array of Arrays?

If I have an object that is declared as
let compoundArray = [Array<String>]
is there a property that would give me the number of strings in all the arrays contained in compoundArray?
I can do it by adding up all the items in each array within:
var totalCount = 0
for array in compoundArray {
totalCount += array.count }
//totalCount = total items in all arrays within compoundArray
But that seems clunky and it seems that swift would have a property/method of Array to do this, no?
Thanks!
You can add the nested array counts with
let count = compoundArray.reduce(0) { $0 + $1.count }
Performance comparison for large arrays (compiled and run on a MacBook Pro in Release configuration):
let N = 20_000
let compoundArray = Array(repeating: Array(repeating: "String", count: N), count: N)
do {
let start = Date()
let count = compoundArray.joined().count
let end = Date()
print(end.timeIntervalSince(start))
// 0.729196012020111
}
do {
let start = Date()
let count = compoundArray.flatMap({$0}).count
let end = Date()
print(end.timeIntervalSince(start))
// 29.841913998127
}
do {
let start = Date()
let count = compoundArray.reduce(0) { $0 + $1.count }
let end = Date()
print(end.timeIntervalSince(start))
// 0.000432014465332031
}
You can use joined or flatMap for that.
Using joined
let count = compoundArray.joined().count
Using flatMap
let count = compoundArray.flatMap({$0}).count
Since you are asking for a property, I thought I'd point out how to create one (for all collections, while we're at it):
extension Collection where Iterator.Element: Collection {
var flatCount: Int {
return self.reduce(0) { $0 + $1.count } // as per Martin R
}
}
Making this recursive seems to be an interesting exercise.

Iterate over two arrays simultaneously

I am new to Swift. I have been doing Java programming. I have a scenario to code for in Swift.
The following code is in Java. I need to code in Swift for the following scenario
// With String array - strArr1
String strArr1[] = {"Some1","Some2"}
String strArr2[] = {"Somethingelse1","Somethingelse2"}
for( int i=0;i< strArr1.length;i++){
System.out.println(strArr1[i] + " - "+ strArr2[i]);
}
I have a couple of arrays in swift
var strArr1: [String] = ["Some1","Some2"]
var strArr2: [String] = ["Somethingelse1","Somethingelse2"]
for data in strArr1{
println(data)
}
for data in strArr2{
println(data)
}
// I need to loop over in single for loop based on index.
Could you please provide your help on the syntaxes for looping over based on index
You can use zip(), which creates
a sequence of pairs from the two given sequences:
let strArr1 = ["Some1", "Some2"]
let strArr2 = ["Somethingelse1", "Somethingelse2"]
for (e1, e2) in zip(strArr1, strArr2) {
print("\(e1) - \(e2)")
}
The sequence enumerates only the "common elements" of the given sequences/arrays. If they have different length then the additional
elements of the longer array/sequence are simply ignored.
With Swift 5, you can use one of the 4 following Playground codes in order to solve your problem.
#1. Using zip(_:_:) function
In the simplest case, you can use zip(_:_:) to create a new sequence of pairs (tuple) of the elements of your initial arrays.
let strArr1 = ["Some1", "Some2", "Some3"]
let strArr2 = ["Somethingelse1", "Somethingelse2"]
let sequence = zip(strArr1, strArr2)
for (el1, el2) in sequence {
print("\(el1) - \(el2)")
}
/*
prints:
Some1 - Somethingelse1
Some2 - Somethingelse2
*/
#2. Using Array's makeIterator() method and a while loop
It is also easy to loop over two arrays simultaneously with a simple while loop and iterators:
let strArr1 = ["Some1", "Some2", "Some3"]
let strArr2 = ["Somethingelse1", "Somethingelse2"]
var iter1 = strArr1.makeIterator()
var iter2 = strArr2.makeIterator()
while let el1 = iter1.next(), let el2 = iter2.next() {
print("\(el1) - \(el2)")
}
/*
prints:
Some1 - Somethingelse1
Some2 - Somethingelse2
*/
#3. Using a custom type that conforms to IteratorProtocol
In some circumstances, you may want to create you own type that pairs the elements of your initials arrays. This is possible by making your type conform to IteratorProtocol. Note that by making your type also conform to Sequence protocol, you can use instances of it directly in a for loop:
struct TupleIterator: Sequence, IteratorProtocol {
private var firstIterator: IndexingIterator<[String]>
private var secondIterator: IndexingIterator<[String]>
init(firstArray: [String], secondArray: [String]) {
self.firstIterator = firstArray.makeIterator()
self.secondIterator = secondArray.makeIterator()
}
mutating func next() -> (String, String)? {
guard let el1 = firstIterator.next(), let el2 = secondIterator.next() else { return nil }
return (el1, el2)
}
}
let strArr1 = ["Some1", "Some2", "Some3"]
let strArr2 = ["Somethingelse1", "Somethingelse2"]
let tupleSequence = TupleIterator(firstArray: strArr1, secondArray: strArr2)
for (el1, el2) in tupleSequence {
print("\(el1) - \(el2)")
}
/*
prints:
Some1 - Somethingelse1
Some2 - Somethingelse2
*/
#4. Using AnyIterator
As an alternative to the previous example, you can use AnyIterator. The following code shows a possible implementation of it inside an Array extension method:
extension Array {
func pairWithElements(of array: Array) -> AnyIterator<(Element, Element)> {
var iter1 = self.makeIterator()
var iter2 = array.makeIterator()
return AnyIterator({
guard let el1 = iter1.next(), let el2 = iter2.next() else { return nil }
return (el1, el2)
})
}
}
let strArr1 = ["Some1", "Some2", "Some3"]
let strArr2 = ["Somethingelse1", "Somethingelse2"]
let iterator = strArr1.pairWithElements(of: strArr2)
for (el1, el2) in iterator {
print("\(el1) - \(el2)")
}
/*
prints:
Some1 - Somethingelse1
Some2 - Somethingelse2
*/
Try This:
zip([0,2,4,6], [1,3,5,7]).forEach {
print($0,$1)
}
zip([0,2,4,6], [1,3,5,7]).forEach {
print($0.0,$0.1)
}
You could also enumerate over one array and used the index to look inside the second array:
Swift 1.2:
for (index, element) in enumerate(strArr1) {
println(element)
println(strArr2[index])
}
Swift 2:
for (index, element) in strArr1.enumerate() {
print(element)
print(strArr2[index])
}
Swift 3:
for (index, element) in strArr1.enumerated() {
print(element)
print(strArr2[index])
}
You could use Range if you still want to use for in.
var strArr1: [String] = ["Some1","Some2"]
var strArr2: [String] = ["Somethingelse1","Somethingelse2"]
for i in Range(start: 0, end: strArr1.count) {
println(strArr1[i] + " - " + strArr2[i])
}
for(var i = 0; i < strArr1.count ; i++)
{
println(strArr1[i] + strArr2[i])
}
That should do it. Never used swift before so make sure to test.
Updated to recent Swift syntax
for i in 0..< strArr1.count {
print(strArr1[i] + strArr2[i])
}
> Incase of unequal count
let array1 = ["some1","some2"]
let array2 = ["some1","some2","some3"]
var iterated = array1.makeIterator()
let finalArray = array2.map({
let itemValue = iterated.next()
return "\($0)\(itemValue != nil ? "-"+itemValue! : EmptyString)" })
// result : ["some1-some1","some2-some2","some3"]

How do I make this extension of Array? [duplicate]

Suppose I have an array and I want to pick one element at random.
What would be the simplest way to do this?
The obvious way would be array[random index]. But perhaps there is something like ruby's array.sample? Or if not could such a method be created by using an extension?
Swift 4.2 and above
The new recommended approach is a built-in method on the Collection protocol: randomElement(). It returns an optional to avoid the empty case I assumed against previously.
let array = ["Frodo", "Samwise", "Merry", "Pippin"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0
If you don't create the array and aren't guaranteed count > 0, you should do something like:
if let randomElement = array.randomElement() {
print(randomElement)
}
Swift 4.1 and below
Just to answer your question, you can do this to achieve random array selection:
let array = ["Frodo", "Samwise", "Merry", "Pippin"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])
The castings are ugly, but I believe they're required unless someone else has another way.
Riffing on what Lucas said, you could create an extension to the Array class like this:
extension Array {
func randomItem() -> Element? {
if isEmpty { return nil }
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
For example:
let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16]
let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>
Swift 4 version:
extension Collection where Index == Int {
/**
Picks a random element of the collection.
- returns: A random element of the collection.
*/
func randomElement() -> Iterator.Element? {
return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
}
}
In Swift 2.2 this can be generalised so that we have:
UInt.random
UInt8.random
UInt16.random
UInt32.random
UInt64.random
UIntMax.random
// closed intervals:
(-3...3).random
(Int.min...Int.max).random
// and collections, which return optionals since they can be empty:
(1..<4).sample
[1,2,3].sample
"abc".characters.sample
["a": 1, "b": 2, "c": 3].sample
First, implementing static random property for UnsignedIntegerTypes:
import Darwin
func sizeof <T> (_: () -> T) -> Int { // sizeof return type without calling
return sizeof(T.self)
}
let ARC4Foot: Int = sizeof(arc4random)
extension UnsignedIntegerType {
static var max: Self { // sadly `max` is not required by the protocol
return ~0
}
static var random: Self {
let foot = sizeof(Self)
guard foot > ARC4Foot else {
return numericCast(arc4random() & numericCast(max))
}
var r = UIntMax(arc4random())
for i in 1..<(foot / ARC4Foot) {
r |= UIntMax(arc4random()) << UIntMax(8 * ARC4Foot * i)
}
return numericCast(r)
}
}
Then, for ClosedIntervals with UnsignedIntegerType bounds:
extension ClosedInterval where Bound : UnsignedIntegerType {
var random: Bound {
guard start > 0 || end < Bound.max else { return Bound.random }
return start + (Bound.random % (end - start + 1))
}
}
Then (a little more involved), for ClosedIntervals with SignedIntegerType bounds (using helper methods described further below):
extension ClosedInterval where Bound : SignedIntegerType {
var random: Bound {
let foot = sizeof(Bound)
let distance = start.unsignedDistanceTo(end)
guard foot > 4 else { // optimisation: use UInt32.random if sufficient
let off: UInt32
if distance < numericCast(UInt32.max) {
off = UInt32.random % numericCast(distance + 1)
} else {
off = UInt32.random
}
return numericCast(start.toIntMax() + numericCast(off))
}
guard distance < UIntMax.max else {
return numericCast(IntMax(bitPattern: UIntMax.random))
}
let off = UIntMax.random % (distance + 1)
let x = (off + start.unsignedDistanceFromMin).plusMinIntMax
return numericCast(x)
}
}
... where unsignedDistanceTo, unsignedDistanceFromMin and plusMinIntMax helper methods can be implemented as follows:
extension SignedIntegerType {
func unsignedDistanceTo(other: Self) -> UIntMax {
let _self = self.toIntMax()
let other = other.toIntMax()
let (start, end) = _self < other ? (_self, other) : (other, _self)
if start == IntMax.min && end == IntMax.max {
return UIntMax.max
}
if start < 0 && end >= 0 {
let s = start == IntMax.min ? UIntMax(Int.max) + 1 : UIntMax(-start)
return s + UIntMax(end)
}
return UIntMax(end - start)
}
var unsignedDistanceFromMin: UIntMax {
return IntMax.min.unsignedDistanceTo(self.toIntMax())
}
}
extension UIntMax {
var plusMinIntMax: IntMax {
if self > UIntMax(IntMax.max) { return IntMax(self - UIntMax(IntMax.max) - 1) }
else { return IntMax.min + IntMax(self) }
}
}
Finally, for all collections where Index.Distance == Int:
extension CollectionType where Index.Distance == Int {
var sample: Generator.Element? {
if isEmpty { return nil }
let end = UInt(count) - 1
let add = (0...end).random
let idx = startIndex.advancedBy(Int(add))
return self[idx]
}
}
... which can be optimised a little for integer Ranges:
extension Range where Element : SignedIntegerType {
var sample: Element? {
guard startIndex < endIndex else { return nil }
let i: ClosedInterval = startIndex...endIndex.predecessor()
return i.random
}
}
extension Range where Element : UnsignedIntegerType {
var sample: Element? {
guard startIndex < endIndex else { return nil }
let i: ClosedInterval = startIndex...endIndex.predecessor()
return i.random
}
}
You can use Swift's built-in random() function as well for the extension:
extension Array {
func sample() -> Element {
let randomIndex = Int(rand()) % count
return self[randomIndex]
}
}
let array = [1, 2, 3, 4]
array.sample() // 2
array.sample() // 2
array.sample() // 3
array.sample() // 3
array.sample() // 1
array.sample() // 1
array.sample() // 3
array.sample() // 1
Another Swift 3 suggestion
private extension Array {
var randomElement: Element {
let index = Int(arc4random_uniform(UInt32(count)))
return self[index]
}
}
Following others answer but with Swift 2 support.
Swift 1.x
extension Array {
func sample() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
Swift 2.x
extension Array {
func sample() -> Element {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
E.g.:
let arr = [2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31]
let randomSample = arr.sample()
An alternative functional implementation with check for empty array.
func randomArrayItem<T>(array: [T]) -> T? {
if array.isEmpty { return nil }
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
return array[randomIndex]
}
randomArrayItem([1,2,3])
Here's an extension on Arrays with an empty array check for more safety:
extension Array {
func sample() -> Element? {
if self.isEmpty { return nil }
let randomInt = Int(arc4random_uniform(UInt32(self.count)))
return self[randomInt]
}
}
You can use it as simple as this:
let digits = Array(0...9)
digits.sample() // => 6
If you prefer a Framework that also has some more handy features then checkout HandySwift. You can add it to your project via Carthage then use it exactly like in the example above:
import HandySwift
let digits = Array(0...9)
digits.sample() // => 8
Additionally it also includes an option to get multiple random elements at once:
digits.sample(size: 3) // => [8, 0, 7]
Swift 3
import GameKit
func getRandomMessage() -> String {
let messages = ["one", "two", "three"]
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: messages.count)
return messages[randomNumber].description
}
Swift 3 - simple easy to use.
Create Array
var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]
Create Random Color
let randomColor = arc4random() % UInt32(arrayOfColors.count)
Set that color to your object
your item = arrayOfColors[Int(randomColor)]
Here is an example from a SpriteKit project updating a SKLabelNode with a random String:
let array = ["one","two","three","four","five"]
let randomNumber = arc4random() % UInt32(array.count)
let labelNode = SKLabelNode(text: array[Int(randomNumber)])
If you want to be able to get more than one random element out of your array with no duplicates, GameplayKit has you covered:
import GameplayKit
let array = ["one", "two", "three", "four"]
let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array)
let firstRandom = shuffled[0]
let secondRandom = shuffled[1]
You have a couple choices for randomness, see GKRandomSource:
The GKARC4RandomSource class uses an algorithm similar to that employed in arc4random family of C functions. (However, instances of this class are independent from calls to the arc4random functions.)
The GKLinearCongruentialRandomSource class uses an algorithm that is faster, but less random, than the GKARC4RandomSource class. (Specifically, the low bits of generated numbers repeat more often than the high bits.) Use this source when performance is more important than robust unpredictability.
The GKMersenneTwisterRandomSource class uses an algorithm that is slower, but more random, than the GKARC4RandomSource class. Use this source when it’s important that your use of random numbers not show repeating patterns and performance is of less concern.
I find using GameKit's GKRandomSource.sharedRandom() works best for me.
import GameKit
let array = ["random1", "random2", "random3"]
func getRandomIndex() -> Int {
let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count)
return randomNumber
or you could return the object at the random index selected. Make sure the function returns a String first, and then return the index of the array.
return array[randomNumber]
Short and to the point.
There is a built-in method on Collection now:
let foods = ["πŸ•", "πŸ”", "🍣", "🍝"]
let myDinner = foods.randomElement()
If you want to extract up to n random elements from a collection you can add an extension like this one:
extension Collection {
func randomElements(_ count: Int) -> [Element] {
var shuffledIterator = shuffled().makeIterator()
return (0..<count).compactMap { _ in shuffledIterator.next() }
}
}
And if you want them to be unique you can use a Set, but the elements of the collection must conform to the Hashable protocol:
extension Collection where Element: Hashable {
func randomUniqueElements(_ count: Int) -> [Element] {
var shuffledIterator = Set(shuffled()).makeIterator()
return (0..<count).compactMap { _ in shuffledIterator.next() }
}
}
Latest swift3 code try it its working fine
let imagesArray = ["image1.png","image2.png","image3.png","image4.png"]
var randomNum: UInt32 = 0
randomNum = arc4random_uniform(UInt32(imagesArray.count))
wheelBackgroundImageView.image = UIImage(named: imagesArray[Int(randomNum)])
I figured out a very different way to do so using the new features introduced in Swift 4.2.
// πŸ‘‡πŸΌ - 1
public func shufflePrintArray(ArrayOfStrings: [String]) -> String {
// - 2
let strings = ArrayOfStrings
//- 3
var stringans = strings.shuffled()
// - 4
var countS = Int.random(in: 0..<strings.count)
// - 5
return stringans[countS]
}
we declared a function with parameters taking an array of Strings and returning a String.
Then we take the ArrayOfStrings in a variable.
Then we call the shuffled function and store that in a variable. (Only supported in 4.2)
Then we declare a variable which saves a shuffled value of total count of the String.
Lastly we return the shuffled string at the index value of countS.
It is basically shuffling the array of strings and then also have a random pick of number of the total number of count and then returning the random index of the shuffled array.

Resources