Increment value in an array of dictionaries - arrays

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

Related

How to use two-dimensions array in Swift?

So I have this array var arrayItinerario: Array<Any> = [] which is intended to hold arrays of type Itinerario, var temporalArray: Array<Itinerario> = []
Next, this arrayItinerario would later be used to access properties from the struct Itinerario from where the array temporalArray type comes from.
cell.siteLabel.text = "\([arrayItinerario[indexPath.section]][indexPath.row].ubicacion)"
The problem is that arrayItinerario is not an Itinerario type object which make it impossible to access ubicacion to make an example
I have tried
let object = [arrayItinerario[indexPath.section]][indexPath.row] as! Itinerario
But the cast throws an error. How can I do to access properties from the arrays temporalArraythat are inside arrayItinerario?
Note: I am using indexPath because I am filling table cells
var arrayItinerario: [[Itinerario]] = []
//fill data
var temporalArray: [Itinerario] = []
arrayItinerario.append(temporalArray)
cell.siteLabel.text = "\(arrayItinerario[indexPath.section][indexPath.row].ubicacion)"
or
var arrayItinerario: Array<Any> = []
var temporalArray: Array<Itinerario> = []
guard let temp = arrayItinerario[indexPath.section] as? Array<Itinerario>{
return
}
cell.siteLabel.text = "\(temp[indexPath.row].ubicacion)"
Here's an implementation I've used in a few projects:
import Foundation
class Array2D<T> {
var cols:Int, rows:Int
var matrix:[T?]
init(cols: Int, rows: Int, defaultValue:T?) {
self.cols = cols
self.rows = rows
matrix = Array(repeating: defaultValue, count: cols*rows)
}
subscript(col:Int, row:Int) -> T? {
get{
return matrix[cols * row + col]
}
set{
matrix[cols * row + col] = newValue
}
}
func colCount() -> Int { self.cols }
func rowCount() -> Int { self.rows }
}
Because it's generic you can store whatever type you like in it. Example for Ints:
// Create 2D array of Ints, all set to nil initially
let arr = Array2D<Int>(cols: 10, rows: 10, defaultValue: nil)

Swift: How to correctly compare String value to multiple values

I'm looking for the best method to compare a string value entered by the user and compare it to the proper Stage and Level value.
As of now I've made a lot of arrays like so
let Stage1Level1 = ["Phone","Computer,Television"]
let Stage1Level2 = ["Horse","Shoe"]
let Stage1Level3 = ["Milk"]
let Stage2Level1 = ["Snow","Sun"]
let Stage2Level2 = ["Smile","Cry","Water","Salt"]
let Stage2Level3 = ["Five"]
and so on...
So instead of making a long if statement checking for which Stage and Level the user entered I'm looking for the most efficient way of doing this.
Something like this:
var currentStage = 1
var currentLogo = 2
#IBAction func textFieldChanged(_ sender: Any) {
if textFieldChangedOut.text? == Stage(currentStage)Level(currentLogo){
print("Contains the value")
}
}
It's not really clear what these string are, but this is definitely the wrong data structure. I suspect you're looking for something like this, an array of stages that each contain an array of levels, which contain an array of strings.
struct Level {
var values: [String]
}
struct Stage {
var levels: [Level]
}
let stages = [
Stage(levels: [
Level(values: ["One", "Two"])
Level(values: ["Horse", "Shoe"]),
Level(values: ["One", "Two"]),
]),
Stage(levels: [
Level(values: ["Snow", "Sun"]),
Level(values: ["Smile", "Cry"]),
Level(values: ["Five", "Six"]),
]),
]
var currentStage = 1
var currentLogo = 2
// Remember that arrays are 0-indexed. If "currentStage" is 1-indexed
// you need to adjust it
let level = stages[currentStage - 1].levels[currentLogo - 1]
let words = level.values
if let text = textFieldChangedOut.text, words.contains(text) {
print("Contains the value")
}
What you're trying to do with dynamically computing the name of the variable is impossible in pure Swift. There are ways to achieve it by bridging to ObjC, but they're not the right way to attack this problem.
I would create a struct of stage, level and the strings and have an array of that struct
struct StageLevel {
let stage: Int
let level: Int
let words: [String]
}
let stageLevelArray: [StageLevel] =
[StageLevel(stage: 1, level: 1, words: ["Hello", "Hi"]),
StageLevel(stage: 1, level: 2, words: ["Red", "Blue", "Green"]),
StageLevel(stage: 2, level: 1, words: ["No", "Yes"])]
then you can filter out all elements for a chosen stage
let levels = stageLevelArray.filter( { $0.stage == 1} )
or filter out for a stage and a level
let selection = stageLevelArray.filter( { $0.stage == 1 && $0.level == 2 } )
or if you only want the levels or arrays
let levels = stageLevelArray.filter( { $0.stage == 1} ).map { $0.level}
let selection = stageLevelArray.filter( { $0.stage == 1 && $0.level == 2 } ).map { $0.words }
Maybe you can understand adding a dictionary to your current data.
let Stage1Level1 = ["Phone","Computer,Television"]
let Stage1Level2 = ["Horse","Shoe"]
let Stage1Level3 = ["Milk"]
let Stage2Level1 = ["Snow","Sun"]
let Stage2Level2 = ["Smile","Cry","Water","Salt"]
let Stage2Level3 = ["Five"]
var currentStage = 1
var currentLogo = 2
var stageDict : [String: [String]] = [:]
stageDict["Stage1Level1"] = Stage1Level1
stageDict["Stage1Level2"] = Stage1Level2
stageDict["Stage1Level3"] = Stage1Level3
stageDict["Stage2Level1"] = Stage2Level1
stageDict["Stage2Level2"] = Stage2Level2
stageDict["Stage2Level3"] = Stage2Level3
//You also can build by this way
[[Stage1Level1, Stage1Level2, Stage1Level3], [Stage2Level1, Stage2Level2,Stage2Level3]]
.enumerated().forEach{ stage in stage.element.enumerated().forEach{
stageDict["Stage\(stage.offset+1)Level\($0.offset+1)"] = $0.element
}
}
#IBAction func textFieldChanged(_ sender: Any) {
if stageDict["Stage\(currentStage)Level\(currentLogo)"]!.contains(textFieldChangedOut.text!) {
print("Contains the value")
}
}

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

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