Optional Int to Arrays in Swift - Average Function - arrays

How can I write an average function in swift in where input in an array of optional Ints? Here's what I wrote so far:
func ave(array: [Int?] -> Double?) {
var mysum = 0
for num in array {
mysum += num
}
return Double(mysum)/Double(array.count)
}
I read a lot of Optional ints but I don't know how to implement that when the input in an array of optional ints... Any help?

Here it is in Swift 2, since it is only a few days away now:
func ave(array: [Int?]) -> Double? {
guard array.filter({ $0 == nil }).isEmpty else {
print("One of the Ints was nil")
return nil
}
return Double(array.reduce(0, { $0 + $1! })) / Double(array.count)
}
The opening guard statement checks array for any nil members, and returns nil after printing a message if it finds any.
If no nil is found, we use a simple reduce statement to calculate the sum of the array members, then divide by the count.
Here are some examples of the results:
ave([1,2,3]) // 2
ave([1,2,nil]) // nil (and the message will print)
ave([]) // Double.NaN (because you're dividing by zero)
If you want it in Swift 1.2, the implementation is not all that different:
func ave(array: [Int?]) -> Double? {
if array.filter({ $0 == nil }).isEmpty {
return Double(array.reduce(0, combine: { $0 + $1! })) / Double(array.count)
} else {
print("One of the Ints was nil")
return nil
}
}

You just need to make an if let check in your for loop.
func ave(array: [Int?])-> Double {
var arraySize = array.count
var mysum = 0
for num in array {
if let num = num{
mysum += num
}else{
arraySize--
println("Is nil")
}
}
return Double(mysum)/Double(arraySize)
}
As you maybe see, I've added a variable called arraySize because you need to check what's the size of your real array. Without the nils. Otherwise your final calculation doesn't work as wanted. Also I've changed your func-header a little bit. There was a mistake in your code before:
func ave(array: [Int?] -> Double?) {
^^^^^^^^^^
The return-value has to be outside of the ():
func ave(array: [Int?])-> Double {

In Swift you can do average func in two lines (you can do this in one line, of course, but then you get duplicate code - array.filter { $0 != nil }):
func average(array: [Int?]) -> Double {
let arrayWhithoutNils = array.filter { $0 != nil }
return arrayWhithoutNils.count > 0 ? (arrayWhithoutNils.map { Double($0!) }.reduce(0, combine: +) / Double(arrayWhithoutNils.count)) : 0
}
print(average([1, 2, 3])) // 2
print(average([nil, 4, 5, nil])) // 4.5

When you have an array with optional elements, it usually helps to use flatmap to first give you an array with no optionals...
func ave ( nums:[Int?] ) -> Double?
{
var answer : Double? = .None
let realInts = nums.flatMap { $0 }
if ( realInts.count > 0 ) {
var accum : Int = 0
realInts.map { accum += $0 }
answer = Double(accum) / Double(realInts.count)
}
return answer
}

This should do the job
func average(numbers: [Int?]) -> Double {
let sum = numbers.reduce(0) { $0 + ($1 ?? 0) }
let numValidElms = numbers.filter { $0 != nil }.count
let delta = numbers.count - numValidElms
if delta > 0 {
println("Found \(delta) nil values")
}
if numValidElms > 0 {
return Double(sum) / Double(numValidElms)
} else {
return 0
}
}
Examples
average([nil]) // 0
average([1,2,3]) // 2
average([1, nil, 2]) // 1.5
Hope this helps.

One more option:
func ave(array: [Int?])-> Double {
var mysum = 0
var c = 0
for num in array {
if let n = num {
mysum += n
c++
}
return Double(mysum)/Double(c)
}

Related

Count hashmap elements with condition for members? [duplicate]

I'm basically looking for the swift equivalent of the follow c++ code:
std::count_if(list.begin(), list.end(), [](int a){ return a % 2 == 0; }); // counts instances of even numbers in list
My problem isn't actually searching for even numbers, of course; simply the general case of counting instances matching a criterion.
I haven't seen a builtin, but would love to hear that I simply missed it.
Like this:
let a: [Int] = ...
let count = a.filter({ $0 % 2 == 0 }).count
An alternative to Aderstedt's version
let a = [ .... ]
let count = a.reduce(0){
(count, element) in
return count + 1 - element % 2
}
My intuition says my way will be faster because it doesn't require the creation of a second array. However, you'd need to profile both methods to be sure.
Edit
Following MartinR's comment about generalisation of the function, here it is
extension SequenceType
{
func countMatchingCondition(condition: (Self.Generator.Element) -> Bool) -> Int
{
return self.reduce(0, combine: { (count, e) in count + (condition(e) ? 1 : 0) })
}
}
let a = [1, 2, 3, 3, 4, 12].countMatchingCondition { $0 % 2 == 0 }
print("\(a)") // Prints 3
Default array:
let array: [Int] = [10, 10, 2, 10, 1, 2, 3]
filter(_:) method
let countOfTen = array.filter({ $0 == 10 }).count // 3
count(where:) method
Update: This Swift 5.0 feature was withdrawn in beta testing because it was causing performance issues for the type checker.
let countOfTen = array.count(where: { $0 == 10 }) // 3
You can use Collection.lazy to have the simplicity of Aderstedt's Answer but with O(1) space.
let array = [1, 2, 3]
let count = array.lazy.filter({ $0 % 2 == 0 }).count
The most compact reduce statement that will do this is:
let a = Array(1 ... 20)
let evencount = a.reduce(0) { $0 + ($1 % 2 == 0 ? 1 : 0) }
Reduce takes two variables: starts with 0 (var $0) then for every element in Array a (var $1) if the value is divisible by 2 with no remainder then add one to your count.
This is also efficient as it does not create an additional array unlike using a.filter(){}.count .
You can also do this with reduce()
let a = Array(1 ... 20)
let evenCount = a.reduce(0) { (accumulator, value) -> Int in
guard value % 2 == 0 else { return accumulator }
return accumulator + 1
}
Almost everything you want to do with the map() and filter functions can actually be done with a reduce although it's not always the most readable.
Swift 5 or later:
public extension Sequence {
func occurrences(where predicate: (Element) throws -> Bool) rethrows -> Int {
try reduce(0) { try predicate($1) ? $0 + 1 : $0 }
}
}
public extension Sequence where Element: Equatable {
func occurrences(of element: Element) -> Int {
reduce(0) { element == $1 ? $0 + 1 : $0 }
}
}
let multiplesOf2 = [1,2,3,4,4,5,4,5].occurrences{$0.isMultiple(of: 2)} // 4
"abcdeabca".occurrences(of: "a") // 3
extension BinaryInteger {
var isOdd: Bool { !isMultiple(of: 2) }
var isEven: Bool { isMultiple(of: 2) }
}
(-4).isOdd // false
(-3).isOdd // true
(-2).isOdd // false
(-1).isOdd // true
0.isOdd // false
1.isOdd // true
2.isOdd // false
3.isOdd // true
4.isOdd // false
(-4).isEven // true
(-3).isEven // false
(-2).isEven // true
(-1).isEven // false
0.isEven // true
1.isEven // false
2.isEven // true
3.isEven // false
4.isEven // true
let odds = [1,2,3,4,4,5,5,11].occurrences(where: \.isOdd) // 5
let evens = [1,2,3,4,4,5,5,11].occurrences(where: \.isEven) // 3

Comparing arrays with -nan

I have two Double arrays with the equal amount of elements. Both of them contain numbers and some NaN values after trigonometric calculations.
I need to compare every element of the first array to every element of the second, find the greater number, and put it into a new third array. At the end, the third array should contain the same amount of elements as first or second array.
If two Nan are compared, I need to display a specific error message "terrible error" at that exact index. So I guess the third array should be String to be able to display both numbers and error messages. If a Double number is compared to NaN, the Double number should always be chosen as the greater.
How do I do all of that?
Here is my code:
import Foundation
var initValue = Double()
var finalValue = Double()
var stepValue = Double()
while true {
print("Enter the starting number of the range")
if let number = readLine(), Double(number) != nil {
initValue = Double(number)!
break
} else {
print("Enter the correct number!")
}
}
while true {
print("Enter the end value of the range")
if let number = readLine(), Double(number) != nil, Double(number)! > initValue {
finalValue = Double(number)!
break
} else {
print("Enter the correct number, which is greater than starting number of the range!")
}
}
while true {
print("Enter delta")
if let number = readLine(), Double(number) != nil {
stepValue = Double(number)!
break
} else {
print("Enter the correct number!")
}
}
var trueArray = [Double]()
for number in stride(from: initValue, through: finalValue, by: stepValue) {
trueArray.append(number)
}
func calcLn () -> [Double] {
let calculatedArray = trueArray.map { log(1-46/sin($0)) }
return calculatedArray
}
func calcTan () -> [String] {
let calculatedArray = trueArray.map { (tan($0)/46) }
return calculatedArray
}
You can use zip to iterate over your 2 arrays concurrently, and then map to transform the pairs of elements into outputs, as you would like them. It's useful to switching on (ln.isNaN, tan.isNaN), and use that to express the various cases and what their results should be.
Here's a rough start:
import Darwin
func promptForDouble(
initialMessage: String,
errorMessage: String,
acceptanceCriteria isAcceptable: (Double) -> Bool = { _ in true }
) -> Double {
print(initialMessage)
while true {
if let number = readLine().flatMap(Double.init), isAcceptable(number) {
return number
}
print(errorMessage)
}
}
let initValue = promptForDouble(
initialMessage: "Enter the starting number of the range",
errorMessage: "Enter the correct number!"
)
let finalValue = promptForDouble(
initialMessage: "Enter the end value of the range",
errorMessage: "Enter the correct number, which is greater than starting number of the range!",
acceptanceCriteria: { initValue < $0 }
)
let stepValue = promptForDouble(
initialMessage: "Enter delta",
errorMessage: "Enter the correct number!"
)
// TODO: give these functions better names!
func calcLn(_ input: [Double]) -> [Double] {
return input.map { log(1 - 46/sin($0)) }
}
func calcTan(_ input: [Double]) -> [Double] {
return input.map { tan($0) / 46 }
}
func mergeResults(lns: [Double], tans: [Double]) -> [Double?] {
return zip(lns, tans).map { ln, tan -> Double? in
switch (ln.isNaN, tan.isNaN) {
case ( true, true): return nil // Return nil to express error. Don't introduce Strings yet.
case (false, true): return ln
case ( true, false): return tan
case (false, false): return max(ln, tan)
}
}
}
func printResults(_ a1: [Double], _ a2: [Double], _ a3: [Double?]) {
for (a, (b, c)) in zip(a1, zip(a2, a3)) {
let resultString = c.map(String.init) ?? "terrible error" // Note: Strings are only introduced at the UI/presentation layer
print("ln: \(a),\ttan: \(b),\tresult: \(resultString)")
}
}
// TODO: give these arrays better names!
let inputs = Array(stride(from: initValue, through: finalValue, by: stepValue))
let array1 = calcLn(inputs)
let array2 = calcTan(inputs)
let array3 = mergeResults(lns: array1, tans: array2)
printResults(array1, array2, array3)

How to mutate an array of integers in-place in swift through filtering

One can filter an array like this in swift:
var numbers = Array(1...1000000)
numbers = numbers.filter( { return $0 % 2 == 0 } )
Is it possible to filter and avoid the copy operation, that occurs when the filtering is done, e.g mutating the original array.
In a similar way to this pseudocode:
numbers.MutablefilterOperation({ return $0 % 2 == 0})
In C++ the equvivalent to what is going on in Swift above would be:
std::vector<int> originalNumbers(1000000);
std::vector<int> newNumbers;
std::copy_if (originalNumbers.begin(), originalNumbers.end(), std::back_inserter(newNumbers), [](int i) { return i % 2 == 0 } );
What I would like to achieve for performance reasons:
std::vector<int> originalNumbers(1000000);
auto pos = std::remove_if(originalNumbers.begin(), originalNumbers.end(), [](int x) { return x % 2 == 0; });
originalNumbers.erase(pos, originalNumbers.end());
This implementation should do the filtering without having to make a temporary copy of the entire array in the process (unless a copy of it is referenced by another variable, see "Copy on Write")
extension Array {
mutating func filterInPlace(isIncluded: (Element) throws -> Bool) rethrows {
var writeIndex = self.startIndex
for readIndex in self.indices {
let element = self[readIndex]
let include = try isIncluded(element)
if include {
if writeIndex != readIndex {
self[writeIndex] = element
}
writeIndex = self.index(after: writeIndex)
}
}
self.removeLast(self.distance(from: writeIndex, to: self.endIndex))
}
}
// example:
var arr = [6,2,6,5,2,5,6,2,2,1,6,7,3]
arr.filterInPlace { $0 % 2 == 1 }
print(arr) // [5, 5, 1, 7, 3]

count numbers in array and order them by count in swift

Is there a easy way to sort an array by the count of numbers? And if a number have the same count put the highest number first.
[2,8,2,6,1,8,2,6,6]
to
[6,6,6,2,2,2,8,8,1]
What you are looking for is a way to get the frequencies of values.
As long as the values are Hashable this function will work:
It extends all sequence types where the Element is Hashable, so an array of Int will work.
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var results : [Generator.Element:Int] = [:]
for element in self {
results[element] = (results[element] ?? 0) + 1
}
return results
}
}
Then you can do this:
let alpha = [2,8,2,6,1,8,2,6,6]
let sorted = alpha.frequencies().sort {
if $0.1 > $1.1 { // if the frequency is higher, return true
return true
} else if $0.1 == $1.1 { // if the frequency is equal
return $0.0 > $1.0 // return value is higher
} else {
return false // else return false
}
}
Even better, you can now create another extension to sequence types.
Now they need to conform to Comparable as well as Hashable
extension SequenceType where Generator.Element : protocol<Hashable,Comparable> {
func sortByFrequency() -> [Generator.Element] {
// the same sort function as before
let sorted = self.frequencies().sort {
if $0.1 > $1.1 {
return true
} else if $0.1 == $1.1 {
return $0.0 > $1.0
} else {
return false
}
}
// this is to convert back from the dictionary to an array
var sortedValues : [Generator.Element] = []
sorted.forEach { // for each time the value was found
for _ in 0..<$0.1 {
sortedValues.append($0.0) // append
}
}
return sortedValues
}
}
Your final usage of all this will look like this :
let sorted = alpha.sortByFrequency() // [6, 6, 6, 2, 2, 2, 8, 8, 1]
Super clean :)
If you prefer a function closer to sort itself you can also use this :
extension SequenceType where Generator.Element : Hashable {
func sortedFrequency(#noescape isOrderedBefore: ((Self.Generator.Element,Int), (Self.Generator.Element,Int)) -> Bool) -> [Generator.Element] {
let sorted = self.frequencies().sort {
return isOrderedBefore($0,$1) // this uses the closure to sort
}
var sortedValues : [Generator.Element] = []
sorted.forEach {
for _ in 0..<$0.1 {
sortedValues.append($0.0)
}
}
return sortedValues
}
}
The extension above converts the array to a frequency dictionary internally and just asks you to input a closure that returns a Bool. Then you can apply different sorting depending on your needs.
Because you pass the closure with the sorting logic to this function the Elements of the SequenceType no longer need to be comparable.
Cheat sheet for all the shorthand:
$0 // first element
$1 // second element
$0.0 // value of first element
$0.1 // frequency of first element
Sorting :
let sortedB = alpha.sortedFrequency {
if $0.1 > $1.1 {
return true
} else if $0.1 == $1.1 {
return $0.0 > $1.0
} else {
return false
}
} // [6, 6, 6, 2, 2, 2, 8, 8, 1]
I'm not sure if this is the most efficient way to do it, but I think it is fairly elegant:
extension Array where Element: Equatable {
func subArrays() -> [[Element]] {
if self.isEmpty {
return [[]]
} else {
let slice = self.filter { $0 == self[0] }
let rest = self.filter { $0 != self[0] }
return rest.isEmpty
? [slice]
: [slice] + rest.subArrays()
}
}
func sortByFrequency(secondarySort: ((Element, Element) -> Bool)? = nil) -> [Element] {
return self.subArrays()
.sort { secondarySort?($0[0], $1[0]) ?? false }
.sort { $0.count > $1.count }
.flatMap { $0 }
}
}
let nums = [2,8,2,6,1,8,2,6,6]
print(nums.sortByFrequency(>)) // [6, 6, 6, 2, 2, 2, 8, 8, 1]
The function subArrays just breaks the array down into an array of sub-arrays for each value in the original array - i.e., you'd get [[2,2,2],[8,8],[6,6,6],[1]] for the input that you provided.
sortByFrequency sorts the output of subArrays and then flatMaps to get the answer.
EDIT: I modified sortByFrequency to add the optional secondarySearch parameter. That allows you to control how you want items that occur at the same frequency to be sorted. Or, just accept the default nil and they won't be sorted by anything other than frequency.
Also, I modified the extension to indicate that Element only needs to conform to Equatable, not Comparable.
//: Playground - noun: a place where people can play
import UIKit
var arr1 = [2,8,2,6,1,8,2,6,6]
var arr2 = [6,6,6,2,2,2,8,8,1]
var counting = [Int: Int]()
// fill counting dictionary
for num in arr1 {
if counting[num] != nil {
counting[num]!++
} else {
counting[num] = 1
}
}
// [6: 3, 2: 3, 8: 2, 1: 1]
print(counting)
func order(i1: Int, i2: Int) -> Bool {
let count1 = counting[i1]
let count2 = counting[i2]
// if counting is the same: compare which number is greater
if count1 == count2 {
return i1 > i2
} else {
return count1 > count2
}
}
// [6, 6, 6, 2, 2, 2, 8, 8, 1]
print(arr1.sort(order))
print(arr2)
Using grouping in Dictionary:
var entries = [1,2,3,3,1,3,5,6,3,4,1,5,5,5,5]
extension Sequence where Element : Hashable {
func byFrequency() -> [Element] {
Dictionary(grouping: self, by: {$0}).sorted{ (a, b) in
a.value.count > b.value.count
}.map { $0.key}
}
}
print(entries.byFrequency().first)
Prints 5

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